With mingw's Msys tool I've successfully build the opus-codec from source 1.1.tar.gz. The build produced some files, amongst which are libopus.a and libopus-0.dll. Now I want to try the trivial-example.c in QtCreator. I added the lib to my .pro-file and included opus.h in my main file. The compiler complains that it can't find the headers that are included in opus.h Shouldn't these be included within the lib? How do I need to setup my application to run the "trivial-example"?
My folder structure is:
main.cpp
opus_lib_test.pro
opus_lib_test.pro.user
include [folder]
opus.h (from the source include folder)
libs [folder]
libopus.a
libopus-0.dll
My .pro-file looks like
QT += core
QT -= gui
TARGET = opus_lib_test
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
INCLUDEPATH += $$PWD/include
LIBS += -L"C:/Qt/Qt5.2.1/Tools/QtCreator/bin/opus_lib_test/libs/" -llibopus
SOURCES += main.cpp
HEADERS += include/opus.h
and my main.cpp is here:
//#include <QCoreApplication>
#include "opus.h"
int main(int argc, char *argv[])
{
// QCoreApplication a(argc, argv);
// return a.exec();
// ----------------------------- trivial_example.c
char *inFile;
FILE *fin;
char *outFile;
FILE *fout;
opus_int16 in[FRAME_SIZE*CHANNELS];
opus_int16 out[MAX_FRAME_SIZE*CHANNELS];
unsigned char cbits[MAX_PACKET_SIZE];
int nbBytes;
/*Holds the state of the encoder and decoder */
OpusEncoder *encoder;
OpusDecoder *decoder;
int err;
if (argc != 3)
{
fprintf(stderr, "usage: trivial_example input.pcm output.pcm\n");
fprintf(stderr, "input and output are 16-bit little-endian raw files\n");
return EXIT_FAILURE;
}
/*Create a new encoder state */
encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err);
if (err<0)
{
fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
/* Set the desired bit-rate. You can also set other parameters if needed.
The Opus library is designed to have good defaults, so only set
parameters you know you need. Doing otherwise is likely to result
in worse quality, but better. */
err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE));
if (err<0)
{
fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
inFile = argv[1];
fin = fopen(inFile, "r");
if (fin==NULL)
{
fprintf(stderr, "failed to open file: %s\n", strerror(errno));
return EXIT_FAILURE;
}
/* Create a new decoder state. */
decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err);
if (err<0)
{
fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
outFile = argv[2];
fout = fopen(outFile, "w");
if (fout==NULL)
{
fprintf(stderr, "failed to open file: %s\n", strerror(errno));
return EXIT_FAILURE;
}
while (1)
{
int i;
unsigned char pcm_bytes[MAX_FRAME_SIZE*CHANNELS*2];
int frame_size;
/* Read a 16 bits/sample audio frame. */
fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin);
if (feof(fin))
break;
/* Convert from little-endian ordering. */
for (i=0;i<CHANNELS*FRAME_SIZE;i++)
in[i]=pcm_bytes[2*i+1]<<8|pcm_bytes[2*i];
/* Encode the frame. */
nbBytes = opus_encode(encoder, in, FRAME_SIZE, cbits, MAX_PACKET_SIZE);
if (nbBytes<0)
{
fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes));
return EXIT_FAILURE;
}
/* Decode the data. In this example, frame_size will be constant because
the encoder is using a constant frame size. However, that may not
be the case for all encoders, so the decoder must always check
the frame size returned. */
frame_size = opus_decode(decoder, cbits, nbBytes, out, MAX_FRAME_SIZE, 0);
if (frame_size<0)
{
fprintf(stderr, "decoder failed: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
/* Convert to little-endian ordering. */
for(i=0;i<CHANNELS*frame_size;i++)
{
pcm_bytes[2*i]=out[i]&0xFF;
pcm_bytes[2*i+1]=(out[i]>>8)&0xFF;
}
/* Write the decoded audio to file. */
fwrite(pcm_bytes, sizeof(short), frame_size*CHANNELS, fout);
}
/*Destroy the encoder state*/
opus_encoder_destroy(encoder);
opus_decoder_destroy(decoder);
fclose(fin);
fclose(fout);
return EXIT_SUCCESS;
}
The header files referenced in opus.h:
#include "opus_types.h"
#include "opus_defines.h"
They are both from source include folder, the same as opus.h. I think your problem will be solved if you copy all .h files (5 including opus.h) from source include folder into include [folder] in your folder structure.
Header files are not included in lib, only cpp files are included. You need to specify header files separately.
Related
I slightly modified the opus provide sample file "trivial_example.c"
I modified it so instead of loading a pcm file from disk, I just create some noise using random numbers. Maybe that is the problem, but I dont see how.
I am using Visual Studio 2019. Windows SDK 10. Windows7 x64.
none of the opus functions return an error.
opus_encode() seems to work. It fills cbits, as expected.
But opus_decode() only fills the output buffer with zeros.
This is opus provided sample code, but it doesnt work. Is there some computer setup I needed to do before using opus.
Ive been trying to get opus to work for days. Please help. Thank you.
#define FRAME_SIZE 960
#define SAMPLE_RATE 48000
#define CHANNELS 2
#define APPLICATION OPUS_APPLICATION_AUDIO
#define BITRATE 64000
#define MAX_FRAME_SIZE 6*960
#define MAX_PACKET_SIZE (3*1276)
int main(int argc, char **argv)
{
char *inFile;
FILE *fin;
char *outFile;
FILE *fout;
opus_int16 in[FRAME_SIZE*CHANNELS];
opus_int16 out[MAX_FRAME_SIZE*CHANNELS];
unsigned char cbits[MAX_PACKET_SIZE];
int nbBytes;
/*Holds the state of the encoder and decoder */
OpusEncoder *encoder;
OpusDecoder *decoder;
int err;
/*Create a new encoder state */
encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err);
if (err<0)
{
fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
/* Set the desired bit-rate. You can also set other parameters if needed.
The Opus library is designed to have good defaults, so only set
parameters you know you need. Doing otherwise is likely to result
in worse quality, but better. */
err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE));
if (err<0)
{
fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
/* Create a new decoder state. */
decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err);
if (err<0)
{
fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
////////////////////////////////////////////////////////////////////// create audio noise
#define RandZeroToOne ((float)rand() / RAND_MAX)
#define RandNegOneToOne (((float)rand() / RAND_MAX)*2.0-1.0)
opus_int16* pcmdata = (opus_int16*)calloc(65536, sizeof(opus_int16));
opus_int16* pDstData = (opus_int16*)calloc(65536, sizeof(opus_int16));
for(short i=0;i<6553;i++)
{
pcmdata[i] = (opus_int16)(RandZeroToOne*32767.0);
if((i&0x1)==0)
pcmdata[i] = -pcmdata[i];
int T=0;
}
//////////////////////////////////////////////////////////////////////
//while (1)
{
int i;
int frame_size;
/* Convert from little-endian ordering. */
for (i=0;i<CHANNELS*FRAME_SIZE;i++)
in[i]=pcmdata[2*i+1]<<8|pcmdata[2*i];
/* Encode the frame. */
nbBytes = opus_encode(encoder, in, FRAME_SIZE, cbits, MAX_PACKET_SIZE);;//<---------------
if (nbBytes<0)
{
fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes));
return EXIT_FAILURE;
}
/* Decode the data. In this example, frame_size will be constant because
the encoder is using a constant frame size. However, that may not
be the case for all encoders, so the decoder must always check
the frame size returned. */
opus_decoder_ctl(decoder, OPUS_RESET_STATE);
frame_size = opus_decode(decoder, cbits, nbBytes, out, MAX_FRAME_SIZE, 0);//<---------------
if (frame_size<0)
{
fprintf(stderr, "decoder failed: %s\n", opus_strerror(frame_size));
return EXIT_FAILURE;
}
/* Convert to little-endian ordering. */
for(i=0;i<CHANNELS*frame_size;i++)
{
pcmdata[2*i]=out[i]&0xFF;
pcmdata[2*i+1]=(out[i]>>8)&0xFF;
}
}
opus_encoder_destroy(encoder);
opus_decoder_destroy(decoder);
return EXIT_SUCCESS;
}
Context
Hello !
I'm currently working on the development of a small library allowing to cut an h.264 video on any frame, but without re-encoding (transcoding) the whole video. The idea is to re-encode only the GOP on which we want to cut, and to rewrite (remux) directly the others GOP.
The avcut project (https://github.com/anyc/avcut) allows to do that, but requires a systematic decoding of each package, and seems to not work with the recent versions of ffmpeg from the tests I could do and from the recent feedbacks in the github issues.
As a beginner, I started from the code examples provided in the ffmpeg documentation, in particular: transcoding.c and remuxing.c.
Problem encountered
The problem I'm having is that I can't get both transcoding and remuxing to work properly at the same time. In particular, depending on the method I use to initialize the AVCodecParameters of the output video stream, transcoding works, or remuxing works:
avcodec_parameters_copy works well for remuxing
avcodec_parameters_from_context works well for transcoding
In case I choose avcodec_parameters_from_context, the transcoded GOP are correctly read by my video player (parole), but the remuxed packets are not read, and ffprobe does not show/detect them.
In case I choose avcodec_parameters_from_context, the remuxing GOP are correctly read by my video player, but the transcoding key_frame are bugged (I have the impression that the b-frame and p-frame are ok), and ffprobe -i return an error about the NAL of the key-frames:
[h264 # 0x55ec8a079300] sps_id 32 out of range
[h264 # 0x55ec8a079300] Invalid NAL unit size (1677727148 > 735).
[h264 # 0x55ec8a079300] missing picture in access unit with size 744
I suspect that the problem is related to the extradata of the packets. Through some experiments on the different attributes of the output AVCodecParameters, it seems that it is the extradata and extradata_size attributes that are responsible for the functioning of one method or the other.
Version
ffmpeg development branch retrieved on 2022-05-17 from https://github.com/FFmpeg/FFmpeg.
Compiled with --enable-libx264 --enable-gpl --enable-decoder=png --enable-encoder=png
Code
My code is written in c++ and is based on two classes: a class defining the parameters and methods on the input file (InputContexts) and a class defining them for the output file (OutputContexts). The code of these two classes is defined in the following files:
contexts.h
contexts.cpp
The code normally involved in the problem is the following:
stream initialization
int OutputContexts::init(const char* out_filename, InputContexts* input_contexts){
int ret;
int stream_index = 0;
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
return ret;
}
av_dump_format(ofmt_ctx, 0, out_filename, 1);
encoders.resize(input_contexts->ifmt_ctx->nb_streams, nullptr);
codecs.resize(input_contexts->ifmt_ctx->nb_streams, nullptr);
// stream mapping
for (int i = 0; i < input_contexts->ifmt_ctx->nb_streams; i++) {
AVStream *out_stream;
AVStream *in_stream = input_contexts->ifmt_ctx->streams[i];
AVCodecContext* decoder_ctx = input_contexts->decoders[i];
// add new stream to output context
out_stream = avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
return ret;
}
// from avcut blog
av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
out_stream->time_base = in_stream->time_base;
// encoder
if (decoder_ctx->codec_type == AVMEDIA_TYPE_VIDEO){
ret = prepare_encoder_video(i, input_contexts);
if (ret < 0){
fprintf(stderr, "Error while preparing encoder for stream #%u\n", i);
return ret;
}
// from avcut
out_stream->sample_aspect_ratio = in_stream->sample_aspect_ratio;
// works well for remuxing
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
if (ret < 0) {
fprintf(stderr, "Failed to copy codec parameters\n");
return ret;
}
// works well for transcoding
// ret = avcodec_parameters_from_context(out_stream->codecpar, encoders[i]);
// if (ret < 0) {
// av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream #%u\n", i);
// return ret;
// }
} else if (decoder_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
...
} else {
...
}
// TODO useful ???
// set current stream position to 0
// out_stream->codecpar->codec_tag = 0;
}
// opening output file in write mode with the ouput context
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", out_filename);
return ret;
}
}
// write headers from output context in output file
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
return ret;
}
return ret;
}
AVCodecContext initialization for encoder
int OutputContexts::prepare_encoder_video(int stream_index, InputContexts* input_contexts){
int ret;
const AVCodec* encoder;
AVCodecContext* decoder_ctx = input_contexts->decoders[stream_index];
AVCodecContext* encoder_ctx;
if (video_index >= 0){
fprintf(stderr, "Impossible to mark stream #%u as video, stream #%u is already registered as video stream.\n",
stream_index, video_index);
return -1; //TODO change this value for correct error code
}
video_index = stream_index;
if(decoder_ctx->codec_id == AV_CODEC_ID_H264){
encoder = avcodec_find_encoder_by_name("libx264");
if (!encoder) {
av_log(NULL, AV_LOG_FATAL, "Encoder libx264 not found\n");
return AVERROR_INVALIDDATA;
}
fmt::print("Encoder libx264 will be used for stream {}.\n", stream_index);
} else {
std::string s = fmt::format("No video encoder found for the given codec_id: {}\n", avcodec_get_name(decoder_ctx->codec_id));
av_log(NULL, AV_LOG_FATAL, s.c_str());
return AVERROR_INVALIDDATA;
}
encoder_ctx = avcodec_alloc_context3(encoder);
if (!encoder_ctx) {
av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n");
return AVERROR(ENOMEM);
}
// from avcut
encoder_ctx->time_base = decoder_ctx->time_base;
encoder_ctx->ticks_per_frame = decoder_ctx->ticks_per_frame;
encoder_ctx->delay = decoder_ctx->delay;
encoder_ctx->width = decoder_ctx->width;
encoder_ctx->height = decoder_ctx->height;
encoder_ctx->pix_fmt = decoder_ctx->pix_fmt;
encoder_ctx->sample_aspect_ratio = decoder_ctx->sample_aspect_ratio;
encoder_ctx->color_primaries = decoder_ctx->color_primaries;
encoder_ctx->color_trc = decoder_ctx->color_trc;
encoder_ctx->colorspace = decoder_ctx->colorspace;
encoder_ctx->color_range = decoder_ctx->color_range;
encoder_ctx->chroma_sample_location = decoder_ctx->chroma_sample_location;
encoder_ctx->profile = decoder_ctx->profile;
encoder_ctx->level = decoder_ctx->level;
encoder_ctx->thread_count = 1; // spawning more threads causes avcodec_close to free threads multiple times
encoder_ctx->codec_tag = 0;
// correct values ???
encoder_ctx->qmin = 16;
encoder_ctx->qmax = 26;
encoder_ctx->max_qdiff = 4;
// end from avcut
// according to avcut, should not be set
// if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER){
// encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// }
ret = avcodec_open2(encoder_ctx, encoder, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", stream_index);
return ret;
}
codecs[stream_index] = encoder;
encoders[stream_index] = encoder_ctx;
return ret;
}
Example
To illustrate my problem, I provide here a test code using the two classes that alternates between transcoding and remuxing at each key-frame encountered in the file using my classes.
trans_remux.cpp
To compile the code:
g++ -o trans_remux trans_remux.cpp contexts.cpp -D__STDC_CONSTANT_MACROS `pkg-config --libs libavfilter` -lfmt -g
Currently the code is using avcodec_parameters_copy (contexts.cpp:333), so it works well for remuxing. If you want to test the version with avcodec_parameters_from_context, pls comment from line 333 to 337 in contexts.cpp and uncomment from line 340 to 344 and recompile.
Do you know how to create empty file pcap with winpcap dll? I buffer filtered packets in program memory and want to save when user click to export to .pcap file.
But when using pcap_open_offline(const char *fname, char *errbuf) can open file only if file exists. I tried fopen and other functions to create file previously (in binary mode too) but unsucessfully.
So how to get pcap_t handle pointer for pcap_dump_open(pcap_t *p, const char *fname) this way?
UPDATED:
I try to use this code
fileHandle = pcap_open_offline(pcap_file_path.c_str(), errbuf);
if (errbuf == nullptr) {
fprintf(stderr, "\nUnable to open the file %s.\n", pcap_file_path.c_str());
return 1;
}
if (fileHandle == nullptr) {
fprintf(stderr, "\nError to open file\n");//HERE IT FAILS
return 1;
}
dumpfile = pcap_dump_open(fileHandle, pcap_file_path.c_str());
if (dumpfile == NULL)
{
fprintf(stderr, "\nError opening output file\n");
return 1;
}
SOLUTION: (Creating a pcap file)
/*create fake handle*/
fileHandle = pcap_open_dead(DLT_EN10MB, 65535);
if (fileHandle == nullptr) {
fprintf(stderr, "\nError to open file\n");
return 1;
}
/* Open the dump file */
dumpfile = pcap_dump_open(fileHandle, file_path.c_str());
if (dumpfile == NULL)
{
fprintf(stderr, "\nError opening output file\n");
return 1;
}
Do you know how to create empty file pcap with winpcap dll? I buffer filtered packets in program memory and want to save when user click to export to .pcap file.
...
So how to get pcap_t handle pointer for pcap_dump_open(pcap_t *p, const char *fname) this way?
pcap_dump_open() returns a pcap_dumper_t * handle for use when writing the file; a pcap_t * is used for capturing or reading, not writing.
What you need to do, if you want to write a pcap file, is use pcap_dump_open(). If you have a pcap_t * from which you're reading or capturing the filtered packets, you should use that pcap_t * in the call to pcap_dump_open().
I have .wav files and I would to encode them using opus, write everything in an .opus file then read it with vlc for example. I have done some code using the opus trivial example but the quality is very poor. In fact, there is a problem, I never write any header, is that normal ? What do I have forgotten ?
#define FRAME_SIZE 960
#define SAMPLE_RATE 48000 //frequence
#define CHANNELS 1 // up to 255
#define APPLICATION OPUS_APPLICATION_AUDIO
#define MAX_FRAME_SIZE 6*960
#define MAX_PACKET_SIZE (3*1276)
#define BUFFER_LEN 1024
int main(int argc, char **argv)
{
char *inFile;
FILE *fin;
char *outFile;
FILE *fout;
opus_int16 in[FRAME_SIZE*CHANNELS];
unsigned char cbits[MAX_PACKET_SIZE];
OpusEncoder *encoder;
int err;
/*Create a new encoder state */
encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err);
if (err<0)
{
fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(512000)); //500 to 512 000 // 350 000 pas trop mal
if (err<0)
{
fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
inFile = "toencode.wav";
fin = fopen(inFile, "r");
if (fin==NULL)
{
fprintf(stderr, "in: failed to open file: %s\n", strerror(errno));
return EXIT_FAILURE;
}
if (err<0)
{
fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
outFile = "encoded.opus";
fout = fopen(outFile, "w");
if (fout==NULL)
{
fprintf(stderr, "failed to open file: %s\n", strerror(errno));
return EXIT_FAILURE;
}
while (1)
{
int i;
unsigned char pcm_bytes[MAX_FRAME_SIZE*CHANNELS*2];
/* Read a 16 bits/sample audio frame. */
fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin);
if (feof(fin))
break;
/* Convert from little-endian ordering. */
for (i=0;i<CHANNELS*FRAME_SIZE;i++)
in[i]=pcm_bytes[2*i+1]<<8|pcm_bytes[2*i];
/* Encode the frame. */
if (opus_encode(encoder, in, FRAME_SIZE, cbits, MAX_PACKET_SIZE)<0)
{
// fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes));
return EXIT_FAILURE;
}
fwrite(in,sizeof(short),sizeof(in),fout);
}
/*Destroy the encoder state*/
opus_encoder_destroy(encoder);
fclose(fin);
fclose(fout);
return EXIT_SUCCESS;
}
I think there is a real problem of how I write the file but I dont't where it comes from, can you please help me ?
To make a playable .opus file you need to construct headers and encapsulate them in a sequence of Ogg pages before writing the stream out. See https://git.xiph.org/?p=opus-tools.git;a=blob;f=src/opusenc.c for an open source implementation.
Note you'll get better results if you use 960 samples for MAX_FRAME_SIZE. Bumping the bitrate to the maximum won't make much of a audible difference either.
Has anyone written any tutorials or have any documentation on how to use GnuPGME so I would be able to write a function such as gpgSign(std::string fileToBeSigned, std::string outPutFileName) in C++?
Below is a C example with verbose comments that does what you are looking for - it is not the most direct approach, but should illustrate the how to accomplish signing a file. It does not handle selection of signers, but the GPGME docs should help you there.
You can save the file and make edits and test directly from the command line. To compile, just save as "gpgsign.c", and execute gcc gpgsign.c -lgpgme -o gpgsign (NOTE: you must have libgpgme installed). Then you can execute the using gpgsign <input file> <output file>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <gpgme.h>
#define fail_if_err(err) \
do { \
if (err) { \
fprintf (stderr, "%s:%d: %s: %s\n", \
__FILE__, __LINE__, gpgme_strsource (err), \
gpgme_strerror (err)); \
exit (1); \
} \
} \
while (0)
void gpgSign(const char *fileToBeSigned, const char *outputFileName) {
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_data_t in, out;
FILE *outputFile;
int BUF_SIZE = 512;
char buf[BUF_SIZE + 1];
int ret;
/* Set the GPGME signature mode
GPGME_SIG_MODE_NORMAL : Signature with data
GPGME_SIG_MODE_CLEAR : Clear signed text
GPGME_SIG_MODE_DETACH : Detached signature */
gpgme_sig_mode_t sigMode = GPGME_SIG_MODE_CLEAR;
/* Begin setup of GPGME */
gpgme_check_version (NULL);
setlocale (LC_ALL, "");
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
#ifndef HAVE_W32_SYSTEM
gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
#endif
/* End setup of GPGME */
// Create the GPGME Context
err = gpgme_new (&ctx);
// Error handling
fail_if_err (err);
// Set the context to textmode
gpgme_set_textmode (ctx, 1);
// Enable ASCII armor on the context
gpgme_set_armor (ctx, 1);
// Create a data object pointing to the input file
err = gpgme_data_new_from_file (&in, fileToBeSigned, 1);
// Error handling
fail_if_err (err);
// Create a data object pointing to the out buffer
err = gpgme_data_new (&out);
// Error handling
fail_if_err (err);
// Sign the contents of "in" using the defined mode and place it into "out"
err = gpgme_op_sign (ctx, in, out, sigMode);
// Error handling
fail_if_err (err);
// Open the output file
outputFile = fopen (outputFileName, "w+");
// Rewind the "out" data object
ret = gpgme_data_seek (out, 0, SEEK_SET);
// Error handling
if (ret)
fail_if_err (gpgme_err_code_from_errno (errno));
// Read the contents of "out" and place it into buf
while ((ret = gpgme_data_read (out, buf, BUF_SIZE)) > 0) {
// Write the contents of "buf" to "outputFile"
fwrite (buf, ret, 1, outputFile);
}
// Error handling
if (ret < 0)
fail_if_err (gpgme_err_code_from_errno (errno));
// Close "outputFile"
fclose(outputFile);
// Release the "in" data object
gpgme_data_release (in);
// Release the "out" data object
gpgme_data_release (out);
// Release the context
gpgme_release (ctx);
}
int
main (int argc, char **argv) {
if (argc != 3) {
printf("Usage: gpgsign <input file> <output file>\n");
exit (1);
}
printf("Signing %s and placing the result into %s\n", argv[1], argv[2]);
gpgSign(argv[1], argv[2]);
return 0;
}
This answer probably comes too late, but if I were you I'd rather use Keyczar which is a high-level crypto toolkit with a simple API. Java, C++, Python bindings are available.
GPGME is still quite low-level IMO for someone who needs crypto functionality without too much tweaking. Of course a crypto expert needs this type of complexity.
Personally, I try to avoid libraries that require me to set up this engine and that context in 100 lines of boilerplate code before I can do something basic... but I am no expert at anything.