Ticket #1548: ffmpeg_dll.cpp

File ffmpeg_dll.cpp, 30.0 KB (added by TheSHEEEP, 4 years ago)

Our ffmpeg dll

Line 
1// ffmpeg_dll.cpp : Definiert die exportierten Funktionen für die DLL-Anwendung.
2//
3
4#include "stdafx.h"
5#include "ffmpeg_dll.h"
6#include "../../ffmpeg/include/stdint.h"
7#include "../../ffmpeg/include/inttypes.h"
8#include "../amr_wb/code/enc/include/interf_enc.h"
9#include "../amr_nb/code/main/interf_enc.h"
10#include <iostream>
11#include <fstream>
12using namespace std;
13
14#ifndef M_PI
15#define M_PI 3.14159265358979323846
16#endif
17
18#define inline _inline
19#define snprintf _snprintf
20
21#include "libavformat/avformat.h"
22#include "libswscale/swscale.h"
23#include <memory.h>
24
25#undef exit
26#define STREAM_PIX_FMT PIX_FMT_YUV420P /* default pix_fmt */
27#define PICTURE_PIX_FMT PIX_FMT_ARGB /* source pix_fmt */
28
29static int sws_flags = SWS_BICUBIC;
30
31// Logging variables
32static ofstream s_logFile;
33
34
35#define MAXPICS 8
36#define MAXPICSIZE 2097152
37static unsigned int gstc_picBufIdx = 0;
38static char gstc_picBufs[ MAXPICS ][MAXPICSIZE];
39static unsigned int gstc_u4MaxQueueSize = 0;
40
41
42static unsigned int gstc_u4Mallocs = 0;
43static unsigned int gstc_u4MaxMallocs = 0;
44
45
46
47DWORD WINAPI Cffmpeg_dll_thread(LPVOID param);
48
49/**
50*       Write ffmpeg logging to the ffmpeg logging file.
51*/
52static void log_callback(void *ptr, int level, const char *fmt, va_list vargs)
53{
54        static char message[8192];   
55        const char *module = NULL;
56
57        // We don't want every nonsense in here
58        if (level > AV_LOG_WARNING)
59                return;
60
61        // Get module name
62    if (ptr)
63    {
64        AVClass *avc = *(AVClass**) ptr;
65        module = avc->item_name(ptr);
66    }
67
68        // Create the actual message
69        vsnprintf_s(message, sizeof(message), fmt, vargs);
70
71        // Skip the "non-strictly-monotonic PTS"
72        // No idea what that is, seems it cannot be fixed.
73        if (strncmp(message,"non-strictly-monotonic PTS", 10) == 0)
74                return;
75
76        // Append the message to the logfile
77        if (module)
78        {
79                s_logFile << module << " -------------------" << endl;
80        }
81        s_logFile << "lvl: " << level << endl << "msg: " << message << endl;
82}
83
84/*
85* add an audio output stream
86*/
87static AVStream *add_audio_stream(Cffmpeg_dll * ptr, AVFormatContext *oc, enum CodecID codec_id )
88{
89        AVCodecContext *c;
90        AVStream *st;
91        AVCodec* codec;
92
93        // Get correct codec
94        codec = avcodec_find_encoder(codec_id);
95        if (!codec) {
96                av_log(NULL, AV_LOG_ERROR, "%s","Codec not found\n");
97                exit(1);
98        }
99
100        // Create stream
101        st = avformat_new_stream(oc, codec);
102        if (!st) {
103                av_log(NULL, AV_LOG_ERROR, "%s","Could not alloc stream\n");
104                exit(1);
105        }
106
107        c = st->codec;
108        c->codec = codec;
109        c->codec_id = codec_id;
110        c->codec_type = AVMEDIA_TYPE_AUDIO;
111
112        /* put sample parameters */
113        c->sample_fmt = ptr->sample_fmt;
114        c->bit_rate = ptr->audio_bit_rate;
115        c->sample_rate = ptr->sample_rate;
116        c->channels = ptr->channels;
117
118        // some formats want stream headers to be separate
119        if(oc->oformat->flags & AVFMT_GLOBALHEADER)
120                c->flags |= CODEC_FLAG_GLOBAL_HEADER;
121
122        return st;
123}
124
125static void open_audio( Cffmpeg_dll * ptr, AVFormatContext *oc, AVStream *st )
126{
127        AVCodecContext *c;
128
129        c = st->codec;
130
131        /* open it */
132        // NEWFFMPEG
133        if (avcodec_open2(c, NULL, NULL) < 0) {
134                av_log(c, AV_LOG_ERROR, "%s","could not open audio codec\n");
135                exit(1);
136        }
137
138        /* init signal generator */
139        ptr->t = 0;
140        ptr->tincr = (float)(2 * M_PI * 110.0 / c->sample_rate);
141        /* increment frequency by 110 Hz per second */
142        ptr->tincr2 = (float)(2 * M_PI * 110.0 / c->sample_rate / c->sample_rate);
143
144        ptr->audio_outbuf_size = 10000;
145        ptr->audio_outbuf = (uint8_t *) av_malloc(ptr->audio_outbuf_size);
146
147        if (c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
148       ptr-> audio_input_frame_size = 10000;
149    else
150       ptr->audio_input_frame_size = c->frame_size;
151    ptr->samples = (int16_t *) av_malloc(ptr->audio_input_frame_size *
152                                                                                av_get_bytes_per_sample(c->sample_fmt) *
153                                                                                c->channels);
154
155        /* ugly hack for PCM codecs (will be removed ASAP with new PCM
156        support to compute the input frame size in samples */
157        /*if (c->frame_size <= 1) {
158                ptr->audio_input_frame_size = ptr->audio_outbuf_size / c->channels;
159                switch(st->codec->codec_id) {
160                case CODEC_ID_PCM_S16LE:
161                case CODEC_ID_PCM_S16BE:
162                case CODEC_ID_PCM_U16LE:
163                case CODEC_ID_PCM_U16BE:
164                        ptr->audio_input_frame_size >>= 1;
165                        break;
166                default:
167                        break;
168                }
169        } else {
170                ptr->audio_input_frame_size = c->frame_size;
171        }
172        ptr->samples = (int16_t *) av_malloc(ptr->audio_input_frame_size * 2 * c->channels);*/
173}
174
175/* prepare a 16 bit dummy audio frame of 'frame_size' samples and
176'nb_channels' channels */
177static void get_audio_frame( Cffmpeg_dll* ptr, int16_t* samples, int frame_size, int nb_channels, int16_t sample_val ) {
178
179        if( ! ptr->fp_sound_input ) sample_val = 0;
180        if ( sample_val == 0 ) memset( samples, 0, sizeof( int16_t ) * frame_size * nb_channels );
181        else int numread = fread( samples, sizeof( int16_t ), frame_size * nb_channels, ptr->fp_sound_input );
182};
183
184static void write_audio_frame( Cffmpeg_dll * ptr, AVFormatContext *oc, AVStream *st, int16_t sample_val )
185{
186        AVCodecContext *c;
187        AVPacket pkt;
188        av_init_packet(&pkt);
189
190        c = st->codec;
191
192        get_audio_frame( ptr, ptr->samples, ptr->audio_input_frame_size, c->channels, sample_val );
193
194        pkt.size= avcodec_encode_audio( c, ptr->audio_outbuf, ptr->audio_outbuf_size, ptr->samples );
195
196        if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)
197                pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
198        pkt.flags |= AV_PKT_FLAG_KEY;
199        pkt.stream_index= st->index;
200        pkt.data= ptr->audio_outbuf;
201
202        /* write the compressed frame in the media file */
203        if (av_write_frame(oc, &pkt) != 0) {
204                av_log(c, AV_LOG_ERROR, "%s","Error while writing audio frame\n");
205                exit(1);
206        }
207}
208
209static void close_audio( Cffmpeg_dll * ptr, AVFormatContext *oc, AVStream *st )
210{
211        //switch ( ptr->audio_codec_id )
212        //{
213        //case CODEC_ID_AAC :
214        //      break;
215        //case CODEC_ID_AMR_NB :
216        //      break;
217        //case CODEC_ID_AMR_WB :
218        //      break;
219        //case CODEC_ID_MP3 :
220        //      break;
221        //}
222
223        avcodec_close( st->codec );
224        av_free( ptr->samples );
225        ptr->samples = NULL;
226        av_free( ptr->audio_outbuf );
227        ptr->audio_outbuf = NULL;
228}
229
230/* add a video output stream */
231static AVStream *add_video_stream( Cffmpeg_dll * ptr, AVFormatContext *oc, enum CodecID codec_id )
232{
233        AVCodecContext *c;
234        AVStream *st; 
235        AVCodec* codec;
236
237        // Get correct codec
238        codec = avcodec_find_encoder(codec_id);
239        if (!codec) {
240                av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found\n");
241                exit(1);
242        }
243
244        // Create stream
245        st = avformat_new_stream(oc, codec);
246        if (!st) {
247                av_log(NULL, AV_LOG_ERROR, "%s","Could not alloc stream\n");
248                exit(1);
249        }
250
251        c = st->codec;
252 
253        /* Get default values */
254        codec = avcodec_find_encoder(codec_id);
255        if (!codec) {
256                av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found (default values)\n");
257                exit(1);
258        }
259        avcodec_get_context_defaults3(c, codec);
260
261        c->codec_id = codec_id;
262        c->codec_type = AVMEDIA_TYPE_VIDEO;
263
264        /* put sample parameters */
265        c->bit_rate = ptr->video_bit_rate;
266        av_log(NULL, AV_LOG_ERROR, " Bit rate: %i", c->bit_rate);
267
268    if (codec_id == CODEC_ID_H264) 
269    {
270        c->qmin = ptr->qmin;
271        c->qmax = ptr->qmax;
272        c->me_method = ptr->me_method;
273        c->me_subpel_quality = ptr->me_subpel_quality;
274        c->i_quant_factor = ptr->i_quant_factor;
275        c->qcompress = ptr->qcompress;
276        c->max_qdiff = ptr->max_qdiff;
277
278                // We need to set the level and profile to get videos that play (hopefully) on all platforms
279                //c->level = 30;
280                c->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
281    }
282
283    /* resolution must be a multiple of two */
284        c->width = ptr->dstWidth; 
285        c->height = ptr->dstHeight; 
286
287        /* time base: this is the fundamental unit of time (in seconds) in terms
288        of which frame timestamps are represented. for fixed-fps content,
289        timebase should be 1/framerate and timestamp increments should be
290        identically 1. */
291        c->time_base.den = ptr->fps;
292        c->time_base.num = 1;
293        c->gop_size = ptr->fps;
294        c->pix_fmt = STREAM_PIX_FMT;
295        c->max_b_frames = 0;
296        if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
297                /* just for testing, we also add B frames */
298                c->max_b_frames = 2;
299        }
300        if (c->codec_id == CODEC_ID_MPEG1VIDEO){
301                /* Needed to avoid using macroblocks in which some coeffs overflow.
302                This does not happen with normal video, it just happens here as
303                the motion of the chroma plane does not match the luma plane. */
304                c->mb_decision=2;
305        }
306        // some formats want stream headers to be separate
307        if(oc->oformat->flags & AVFMT_GLOBALHEADER)
308                c->flags |= CODEC_FLAG_GLOBAL_HEADER;
309
310        return st;
311}
312
313static AVFrame *alloc_picture( enum PixelFormat pix_fmt, int width, int height )
314{
315        AVFrame *picture;
316        uint8_t *picture_buf;
317        int size;
318
319        picture = avcodec_alloc_frame();
320        if (!picture)
321                return NULL;
322        size = avpicture_get_size(pix_fmt, width, height);
323        picture_buf = (uint8_t *) av_malloc(size);
324        if (!picture_buf) {
325                av_free(picture);
326                return NULL;
327        }
328        avpicture_fill((AVPicture *)picture, picture_buf,
329                pix_fmt, width, height);
330        return picture;
331}
332
333static void open_video( Cffmpeg_dll * ptr, AVFormatContext *oc, AVStream *st )
334{
335        AVCodecContext *c;
336        AVCodec* codec;
337
338        c = st->codec;
339    c->thread_count = ptr->threads;
340       
341        codec = avcodec_find_encoder(c->codec_id);
342        if (!codec) {
343                av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found (default values)\n");
344                exit(1);
345        }
346
347        /* open the codec */
348        if (avcodec_open2(c, codec, NULL) < 0) {
349                av_log(c, AV_LOG_ERROR, "%s","could not open video codec\n");
350                exit(1);
351        }
352
353        ptr->video_outbuf = NULL;
354        if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
355                /* allocate output buffer */
356                /* XXX: API change will be done */
357                /* buffers passed into lav* can be allocated any way you prefer,
358                as long as they're aligned enough for the architecture, and
359                they're freed appropriately (such as using av_free for buffers
360                allocated with av_malloc) */
361                ptr->video_outbuf_size = 200000;
362                ptr->video_outbuf = (uint8_t *) av_malloc( ptr->video_outbuf_size );
363        }
364
365        /* allocate the encoded raw picture */
366        ptr->picture = alloc_picture( c->pix_fmt, c->width, c->height );
367        if ( !ptr->picture ) 
368        {
369                av_log(c, AV_LOG_ERROR, "%s","Could not allocate picture\n");
370                exit(1);
371        }
372
373        /* if the output format is not YUV420P, then a temporary YUV420P
374        picture is needed too. It is then converted to the required
375        output format */
376        ptr->tmp_picture = NULL;
377        if ( c->pix_fmt != PICTURE_PIX_FMT ) 
378        {
379                ptr->tmp_picture = alloc_picture( PICTURE_PIX_FMT, ptr->srcWidth, ptr->srcHeight );
380                if ( !ptr->tmp_picture ) 
381                {
382                        av_log(c, AV_LOG_ERROR, "%s","Could not allocate temporary picture\n");
383                        exit(1);
384                }
385        }
386}
387
388/* copy the bytes of the source image resorted in to the destination image */
389static void fill_image( AVFrame *pict, void * pic, int pic_size, int frame_index, int width, int height )
390{
391        int pic_idx = pic_size-( width*4 )-3;
392        char * pict_dst = (char *)pict->data[0];
393        char* pic_c = (char*)pic;
394
395        for( int i = 0; i < height; i++ )
396        {
397                if ( pic_idx-width*4 < 0 ) break;
398                int idx_dst = i * width * 4;
399                for ( int j = 0; j < width; j++ )
400                {
401                        int dst_idx = idx_dst+(j*4);
402                        int pict_idx = pic_idx+(j*4);
403                        pict_dst[dst_idx+0] = pic_c[pict_idx+0]; // alpha
404                        pict_dst[dst_idx+1] = pic_c[pict_idx+3]; // blue
405                        pict_dst[dst_idx+2] = pic_c[pict_idx+2]; // green
406                        pict_dst[dst_idx+3] = pic_c[pict_idx+1]; // red
407                }
408                pic_idx -= width*4;
409        }
410
411        pict->data[0] = (uint8_t *)pict_dst;
412}
413
414static void write_video_frame( Cffmpeg_dll * ptr, AVFormatContext *oc, AVStream *st, int lastFrame, void * pic, int pic_size )
415{
416        int out_size, ret;
417        AVCodecContext *c;
418        //AVFrame* tempPic;
419        static struct SwsContext *img_convert_ctx = NULL;
420
421        c = st->codec;
422
423        if (ptr->frame_count >= lastFrame ) 
424        {
425                /* no more frame to compress. The codec has a latency of a few
426                frames if using B frames, so we get the last frames by
427                passing the same picture again */
428        } 
429        else 
430        {
431                if (c->pix_fmt != PICTURE_PIX_FMT) 
432                {
433                        /* as we only generate a YUV420P picture, we must convert it
434                        to the codec pixel format if needed */
435                        if (ptr->img_convert_ctx == NULL) 
436                        {
437                                ptr->img_convert_ctx = sws_getContext( ptr->srcWidth, ptr->srcHeight,
438                                        PICTURE_PIX_FMT,
439                                        c->width, c->height,
440                                        c->pix_fmt,
441                                        sws_flags, NULL, NULL, NULL );
442                                if (ptr->img_convert_ctx == NULL) 
443                                {
444                                        av_log(c, AV_LOG_ERROR, "%s","Cannot initialize the conversion context\n");
445                                        exit(1);
446                                }
447                        }
448                        fill_image(ptr->tmp_picture, pic, pic_size, ptr->frame_count, ptr->srcWidth, ptr->srcHeight );
449
450                        sws_scale(ptr->img_convert_ctx, ptr->tmp_picture->data, ptr->tmp_picture->linesize,
451                                0, ptr->srcHeight, ptr->picture->data, ptr->picture->linesize);
452                } 
453                else 
454                {
455                        //fill_yuv_image(picture, frame_count, c->width, c->height);
456                        ptr->picture->data[0]= (uint8_t*)pic;
457                }
458        }
459
460
461        if (oc->oformat->flags & AVFMT_RAWPICTURE) 
462        {
463                /* raw video case. The API will change slightly in the near
464                futur for that */
465                AVPacket pkt;
466               
467                (&pkt);
468
469                pkt.flags |= AV_PKT_FLAG_KEY;
470                pkt.stream_index= st->index;
471                pkt.data= (uint8_t *)ptr->picture;
472                pkt.size= sizeof(AVPicture);
473
474                //ret = av_interleaved_write_frame( oc, &pkt ); // Seems to cause a memory leak
475                ret = av_write_frame(oc, &pkt);
476        } 
477        else 
478        {
479                /*char buffer[4096];
480                sprintf(buffer, "C:\\zoobe\\testing\\yuvfile%i.yuv", ptr->frame_count);
481                ofstream testFile;
482                testFile.open(buffer, ios_base::binary | ios_base::out | ios_base::trunc);
483                testFile.write((char*)ptr->picture->data[0], ptr->picture->linesize[0]*360);
484                testFile.write((char*)ptr->picture->data[1], ptr->picture->linesize[1]*360/2);
485                testFile.write((char*)ptr->picture->data[2], ptr->picture->linesize[2]*360/2);
486                testFile.close();*/
487
488                //Sleep(3);
489                /* encode the image */
490                out_size = avcodec_encode_video( c, ptr->video_outbuf, ptr->video_outbuf_size, ptr->picture );
491                /* if zero size, it means the image was buffered */
492                if (out_size > 0) 
493                {
494                        AVPacket pkt;
495                        av_init_packet(&pkt);
496                        if (c->coded_frame->pts != AV_NOPTS_VALUE)
497                                pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
498                        if(c->coded_frame->key_frame)
499                                pkt.flags |= AV_PKT_FLAG_KEY;
500                        pkt.stream_index= st->index;
501                        pkt.data= ptr->video_outbuf;
502                        pkt.size= out_size;
503
504                        /* write the compressed frame in the media file */
505                        //ret = av_interleaved_write_frame(oc, &pkt); // Seems to cause a memory leak
506                        ret = av_write_frame(oc, &pkt); 
507                } 
508                else 
509                {
510                        ret = 0;
511                }
512        }
513        if (ret != 0) 
514        {
515                av_log(c, AV_LOG_ERROR, "%s","Error while writing video frame\n");
516                exit(1);
517        }
518        ptr->frame_count++;
519}
520
521static void close_video( Cffmpeg_dll * ptr, AVFormatContext *oc, AVStream *st )
522{
523    /* flush buffer */
524        /*
525    int out_size = avcodec_encode_video( st->codec, ptr->video_outbuf, ptr->video_outbuf_size, NULL );
526        if (out_size > 0)
527        {
528                AVPacket pkt;
529                av_init_packet(&pkt);
530                pkt.stream_index= st->index;
531                pkt.data= ptr->video_outbuf;
532                pkt.size= out_size;
533                av_interleaved_write_frame( oc, &pkt );
534    }
535        */
536
537        avcodec_close( st->codec );
538        av_free( ptr->picture->data[0] );
539        av_free( ptr->picture);
540        ptr->picture = NULL;
541        if ( ptr->tmp_picture ) 
542        {
543                av_free( ptr->tmp_picture->data[0] );
544                av_free( ptr->tmp_picture );
545                ptr->tmp_picture = NULL;
546        }
547        av_free( ptr->video_outbuf );
548        ptr->video_outbuf = NULL;
549}
550
551static CodecID GetCodecByString( char * codec )
552{
553        CodecID res = CODEC_ID_NONE;
554       
555        if ( strcmp(codec, "Mpeg4-Part 10") == 0 )
556        {
557                res = CODEC_ID_H264; // CODEC_ID_MPEG4;
558        } 
559        else if ( strcmp(codec, "MPEG2") == 0 )
560        {
561                res = CODEC_ID_MPEG2VIDEO;
562        }
563        else if ( strcmp(codec, "MP2") == 0 )
564        {
565                res = CODEC_ID_MP2;
566        }
567        else if ( strcmp(codec, "PCM-S16LE") == 0 )
568        {
569                res = CODEC_ID_PCM_S16LE;
570        }
571        else if ( strcmp(codec, "Mpeg4-Part 2") == 0 )
572        {
573                res = CODEC_ID_MPEG4;
574        }
575        else if ( strcmp(codec, "h263") == 0 )
576        {
577                res = CODEC_ID_H263;
578        }
579        else if ( strcmp(codec, "AAC-LC/HE") == 0 )
580        {
581                res = CODEC_ID_AAC;
582        }
583        else if ( strcmp(codec, "AMR-NB") == 0 )
584        {
585                res = CODEC_ID_AMR_NB;
586        }
587        else if ( strcmp(codec, "AMR-WB") == 0 )
588        {
589                res = CODEC_ID_AMR_WB;
590        }
591        else if ( strcmp(codec, "MP3") == 0 )
592        {
593                res = CODEC_ID_MP3;
594        }
595
596        return res;
597}
598
599FFMPEG_DLL_API Cffmpeg_dll * Create_Cffmpeg_dll()
600{
601        return ( Cffmpeg_dll* )new Cffmpeg_dll;
602}
603
604FFMPEG_DLL_API int Delete_Cffmpeg_dll( Cffmpeg_dll * ptr )
605{
606        delete ptr;
607        return 0;
608}
609
610//
611// Dies ist das Beispiel einer exportierten Funktion.
612FFMPEG_DLL_API int InitVideo_ffmpeg_dll(Cffmpeg_dll * ptr, 
613                                                                                const char * filename, 
614                                                                                const char * soundname,
615                                                                                const char * logfilePath)
616{
617        if ( ptr->fmt ) ptr->fmt = NULL;
618        if ( ptr->oc ) ptr->oc = NULL;
619        if( ptr->audio_st ) ptr->audio_st = NULL;
620        if ( ptr->video_st ) ptr->video_st = NULL;
621        if ( ptr->audio_pts > 0.0 ) ptr->audio_pts = 0.0;
622        if( ptr->video_pts > 0.0 ) ptr->video_pts = 0.0f;
623
624        gstc_u4Mallocs = 0;
625
626        // Open the logfile
627        s_logFile.open(logfilePath, ios::app | ios::out);
628        s_logFile << "-----------------------------------------------------" << endl;
629        s_logFile << "Initializing new ffmpeg video" << endl;
630
631        /* create pic queue */
632    ptr->pictureQueue = new std::queue<Picture>;
633
634        //avcodec_init();
635        avcodec_register_all();
636        av_register_all();
637
638        // Set log texts to be handled by our own function
639        av_log_set_callback(log_callback);
640        av_log_set_level(AV_LOG_WARNING);
641
642        s_logFile << "libav and log callback init complete." << endl;
643
644        /* auto detect the output format from the name. default is
645        mpeg. */
646        ptr->fmt = av_guess_format( NULL, filename, NULL );
647        ptr->audio_codec_id = GetCodecByString(ptr->audioCodec);
648        if (ptr->audio_codec_id == CODEC_ID_NONE)
649        {
650                ptr->audio_codec_id = CODEC_ID_AAC;
651        }
652        ptr->video_codec_id = GetCodecByString(ptr->videoCodec);
653        if (ptr->video_codec_id == CODEC_ID_NONE)
654        {
655                ptr->video_codec_id = CODEC_ID_H264;
656        }
657
658        if ( !ptr->fmt ) 
659        {
660                printf("Could not deduce output format from file extension: using MPEG.\n");
661                ptr->fmt = av_guess_format( "mpeg", NULL, NULL );
662        }
663        if ( !ptr->fmt ) 
664        {
665                fprintf( stderr, "Could not find suitable output format\n" );
666                return 1;
667        }
668
669        ptr->fmt->video_codec = ptr->video_codec_id;
670        ptr->fmt->audio_codec = ptr->audio_codec_id;
671
672        s_logFile << "Got correct formats: " << ptr->video_codec_id << "/" << ptr->audio_codec_id << endl;
673
674        /* open the sound input file, if needed */
675        if ( strlen( soundname ) > 0 ) 
676        {
677                if ( fopen_s( &ptr->fp_sound_input, soundname, "rb" ) != 0  ) {
678
679                        av_log(ptr->oc, AV_LOG_ERROR, "Could not open '%s'\n", soundname );
680                        ptr->fp_sound_input = NULL;
681                        ptr->channels = 1;
682                }
683                else {
684
685                        // Header operations
686                        // See here: http://de.wikipedia.org/wiki/RIFF_WAVE
687
688                        // Get the header size of the audio file
689                        // 16 is initial size, until the rest-of-the-header-size value comes
690                        // Skip to and read the value
691                        int headerRest = 0;
692                        fseek(ptr->fp_sound_input, 16, SEEK_SET);       
693                        fread((void*)&headerRest, 4, 1, ptr->fp_sound_input);           
694
695                        // Get the number of channels
696                        // Skip to and read the value
697                        fseek(ptr->fp_sound_input, 2, SEEK_CUR);
698                        fread((void*)&ptr->channels, 2, 1, ptr->fp_sound_input);
699                        s_logFile << "Audio channels: " << ptr->channels << endl;
700
701                        // Skip to the end of the header
702                        // - 4 because of the last seek & read
703                        // + 8 because of the header of the data section
704                        fseek(ptr->fp_sound_input, headerRest - 4 + 8, SEEK_CUR);
705                        s_logFile << "Opened audio input file." << endl;
706                };
707        };
708
709       
710
711        /* allocate the output media context */
712        // NEWFFMPEG
713        //ptr->oc = avformat_alloc_context();
714        avformat_alloc_output_context2(&(ptr->oc), NULL, NULL, filename);
715        if ( !ptr->oc ) 
716        {
717                av_log(ptr->oc, AV_LOG_ERROR, "%s","Memory error\n");
718                return 1;
719        }
720        ptr->oc->oformat = ptr->fmt;
721
722        // Create the filename
723        // NEWFFMPEG
724        //_snprintf_s( ptr->oc->filename, sizeof( ptr->oc->filename), strlen(filename), "%s", filename );
725
726        /* add the audio and video streams using the format codecs
727        and initialize the codecs */
728        ptr->video_st = NULL;
729        ptr->audio_st = NULL;
730        if ( ptr->fmt->video_codec != CODEC_ID_NONE ) 
731        {
732                ptr->video_st = add_video_stream( ptr, ptr->oc, ptr->fmt->video_codec );
733        }
734        if ( ptr->fmt->audio_codec != CODEC_ID_NONE ) 
735        {
736                ptr->audio_st = add_audio_stream( ptr, ptr->oc, ptr->fmt->audio_codec );
737        }
738
739        s_logFile << "Added video and audio stream." << endl;
740
741        /* set the output parameters (must be done even if no
742        parameters). */
743        // NEWFFMPEG
744        /*if ( av_set_parameters( ptr->oc, NULL) < 0 )
745        {
746                fprintf( stderr, "Invalid output format parameters\n" );
747                return 1;
748        }*/
749
750        // Responsible for dumping some facts/metadata/etc. to the logging
751        av_dump_format(ptr->oc, 0, filename, 1);
752
753        /* now that all the parameters are set, we can open the audio and
754        video codecs and allocate the necessary encode buffers */
755        if ( ptr->video_st )
756                open_video(ptr, ptr->oc, ptr->video_st);
757        if ( ptr->audio_st )
758                open_audio(ptr, ptr->oc, ptr->audio_st);
759
760        s_logFile << "Opened video and audio codecs." << endl;
761
762        /* open the output file, if needed */
763        if ( !( ptr->fmt->flags & AVFMT_NOFILE ) ) 
764        {
765        // NEWFFMPEG
766                /*if (url_fopen( &ptr->oc->pb, filename, URL_WRONLY ) < 0) */
767                if (avio_open( &ptr->oc->pb, filename, AVIO_FLAG_WRITE) < 0) 
768                {
769                        s_logFile << "Could not open" << filename << "." << endl;
770                        fprintf( stderr, "Could not open '%s'\n", filename );
771                        return 1;
772                }
773        }
774
775        s_logFile << "Opened output file." << endl;
776
777        /* write the stream header, if any */
778        // NEWFFMPEG
779        //av_write_header( ptr->oc );
780        avformat_write_header(ptr->oc, NULL);
781
782        s_logFile << "Written header. Initialization complete. Starting own thread now." << endl;
783        s_logFile << "-----------------------------------------------------" << endl;
784
785        /* Write all audio */
786        if ( ptr->fp_sound_input != NULL )
787        {
788                while ( !feof(ptr->fp_sound_input) )
789                {
790                        write_audio_frame( ptr, ptr->oc, ptr->audio_st, -1 );
791                }
792        }
793
794    /* start encoder thread */
795    ptr->thread = CreateThread(0, 0, Cffmpeg_dll_thread, ptr, 0, 0);
796
797        ptr->video_finished = FALSE;
798        return 0;
799}
800
801int EncodePictureReal_ffmpeg_dll( Cffmpeg_dll * ptr, int frame, void * pic, int pic_size, int vStart, int soundOffset, int lStart, int lEnd, int vEnd );
802
803
804FFMPEG_DLL_API int EncodePicture_ffmpeg_dll( Cffmpeg_dll * ptr, int frame, void * pic, int pic_size, int vStart, int soundOffset, int lStart, int lEnd, int vEnd )
805{
806    Picture picture;
807    picture.frame = frame;
808    if( pic_size >= MAXPICSIZE ) {
809               
810                picture.pic = malloc(pic_size);
811                picture.bFree = true;
812                ++gstc_u4Mallocs;
813        }
814        else {
815       
816                picture.pic = gstc_picBufs[ gstc_picBufIdx++ ];
817                if( ! ( gstc_picBufIdx < MAXPICS ) ) gstc_picBufIdx = 0;
818                picture.bFree = false;
819        };
820
821    memcpy(picture.pic, pic, pic_size);
822    picture.pic_size = pic_size;
823    picture.vStart = vStart;
824    picture.soundOffset = soundOffset;
825    picture.lStart = lStart;
826    picture.lEnd = lEnd;
827    picture.vEnd = vEnd;
828
829    ptr->QueuePicture(picture);
830
831    if (frame >= vEnd && !ptr->video_finished )
832        {
833                CloseVideo_ffmpeg_dll( ptr );
834    }
835
836    return 0;
837}
838
839int EncodePictureReal_ffmpeg_dll( Cffmpeg_dll * ptr, int frame, void * pic, int pic_size, int vStart, int soundOffset, int lStart, int lEnd, int vEnd )
840{
841        bool picEncoded = false;
842
843        if ( frame > vEnd ) return false;
844
845        double delay = (double)soundOffset * ptr->video_st->time_base.num / ptr->video_st->time_base.den;
846        while (!picEncoded)
847        {
848                /* compute current audio and video time */
849                if ( ptr->audio_st )
850                {
851                        ptr->audio_pts = (double)ptr->audio_st->pts.val * ptr->audio_st->time_base.num / ptr->audio_st->time_base.den;
852                }
853                else
854                {
855                        ptr->audio_pts = 0.0;
856                }
857
858                if ( ptr->video_st )
859                {
860                        ptr->video_pts = (double)ptr->video_st->pts.val * ptr->video_st->time_base.num / ptr->video_st->time_base.den;
861                }
862                else
863                {
864                        ptr->video_pts = 0.0;
865                }
866
867                /* write audio and video frames */
868                if (false && !ptr->video_st && ( ptr->video_st && ptr->audio_st && ptr->audio_pts < ptr->video_pts) ) 
869                {
870                        if ( ptr->audio_pts < delay )
871                        {
872                                // Write silence (yeah, 0 is silence!)
873                                write_audio_frame( ptr, ptr->oc, ptr->audio_st, 0 );
874                        } 
875                        else
876                        {
877                                // Write audio (yeah, -1 is actual audio!)
878                                write_audio_frame( ptr, ptr->oc, ptr->audio_st, -1 );
879                        }
880                } 
881                else 
882                {
883                        write_video_frame( ptr, ptr->oc, ptr->video_st, vEnd, pic, pic_size );
884                        picEncoded = true;
885                }
886        }
887        return 0;
888}
889
890FFMPEG_DLL_API int CloseVideo_ffmpeg_dll( Cffmpeg_dll * ptr )
891{
892        s_logFile << "CloseVideo_ffmpeg_dll( Cffmpeg_dll * ptr = " << ptr << " ) entry." << endl;
893        s_logFile << "max queue size so far = " << gstc_u4MaxQueueSize << endl;
894
895        if( gstc_u4Mallocs > gstc_u4MaxMallocs ) gstc_u4MaxMallocs = gstc_u4Mallocs;
896
897        s_logFile << "mallocs = " << gstc_u4Mallocs << ", max mallocs so far = " << gstc_u4Mallocs << endl;
898
899        //if (ptr->video_finished) return 0;
900
901    /* wait for encoder thread to finish */
902        if( ptr->thread ) {
903
904                WaitForSingleObject(ptr->thread, INFINITE);
905                CloseHandle(ptr->thread);
906                ptr->thread = 0;
907        };
908
909        /* write the trailer, if any.  the trailer must be written
910        * before you close the CodecContexts open when you wrote the
911        * header; otherwise write_trailer may try to use memory that
912        * was freed on av_codec_close() */
913        if( ptr->oc ) av_write_trailer( ptr->oc );
914
915        /* close each codec */
916        if ( ptr->video_st && ptr->oc ) close_video( ptr, ptr->oc, ptr->video_st );
917        ptr->video_st = NULL;
918        if ( ptr->audio_st ) close_audio( ptr, NULL, ptr->audio_st );
919        ptr->audio_st = NULL;
920
921        if( !( ptr->fmt->flags & AVFMT_NOFILE ) )  {
922
923                if( ptr->oc ) {
924
925                        if( ptr->oc->pb ) {
926                                /* close the output file */
927        // NEWFFMPEG url_fclose
928                                avio_close( ptr->oc->pb );
929                                ptr->oc->pb = NULL;
930                        };
931                };
932        }
933
934        if ( ptr->fp_sound_input ) {
935
936                fclose( ptr->fp_sound_input );
937                ptr->fp_sound_input = NULL;
938        }
939
940        /* free the context, includes streams */
941        if( ptr->oc ) avformat_free_context( ptr->oc );
942        ptr->oc = NULL;
943    ptr->video_finished = TRUE; 
944
945        /* free sws context */
946        if( ptr->img_convert_ctx ) sws_freeContext(ptr->img_convert_ctx);
947        ptr->img_convert_ctx = 0;
948
949        /* delete pic queue */
950    if( ptr->pictureQueue ) delete ptr->pictureQueue;
951        ptr->pictureQueue = NULL;
952
953        if( s_logFile.is_open() ) {
954
955                s_logFile << "CloseVideo_ffmpeg_dll( Cffmpeg_dll * ptr = " << ptr << " ) exit." << endl;
956                // Close the logfile
957                s_logFile.close();
958        };
959
960        return 0;
961}
962
963// Dies ist der Konstruktor einer Klasse, die exportiert wurde.
964// Siehe ffmpeg_dll.h für die Klassendefinition.
965Cffmpeg_dll::Cffmpeg_dll():
966                        skippedFirst(false),
967            thread(NULL),
968                        t( 0.0f ),
969                        tincr( 0.0f ),
970                        tincr2( 0.0f ),
971                        samples( NULL ),
972                        audio_outbuf( NULL ),
973                        audio_outbuf_size( 0 ),
974                        audio_input_frame_size( 0 ),
975                        fp_sound_input( NULL ),
976                        picture( NULL ),
977                        tmp_picture( NULL ),
978                        video_outbuf( NULL ),
979                        frame_count( 0 ),
980                        video_outbuf_size( 0 ),
981                        fmt( NULL ),
982                        oc( NULL ),
983                        audio_st( NULL ), 
984                        video_st( NULL ),
985                        audio_pts( 0.0 ), 
986                        video_pts( 0.0 ),
987                        srcWidth( 640 ),
988                        srcHeight( 360 ),
989                        dstWidth( 640 ),
990                        dstHeight( 360 ),
991                        img_convert_ctx( NULL ),
992                        audio_codec_id( CODEC_ID_NONE ),
993                        video_codec_id( CODEC_ID_NONE ),
994                        video_bit_rate( 400000 ),
995            qmin(10),
996            qmax(30),
997            me_method(ME_HEX),
998            me_subpel_quality(5),
999            i_quant_factor(0.71f),
1000            qcompress(0.6f),
1001            max_qdiff(4),
1002                        fps(30),
1003
1004                        sample_fmt( AV_SAMPLE_FMT_S16 ),
1005                        audio_bit_rate( 128000 ),
1006                        sample_rate( 44100 ),
1007                        channels( 1 ),
1008
1009
1010                        video_finished( TRUE ),
1011
1012            threads(0)
1013{
1014    InitializeCriticalSection(&this->queueLock);
1015}
1016// Dies ist der Destruktor einer Klasse, die exportiert wurde.
1017// Siehe ffmpeg_dll.h für die Klassendefinition.
1018Cffmpeg_dll::~Cffmpeg_dll()
1019{
1020    DeleteCriticalSection(&this->queueLock);
1021
1022
1023    /* wait for encoder thread to finish */
1024        if( this->thread ) {
1025
1026                WaitForSingleObject(this->thread, INFINITE);
1027                CloseHandle(this->thread);
1028                this->thread = 0;
1029        };
1030
1031        /* close each codec */
1032        if ( this->video_st && this->oc ) close_video( this, this->oc, this->video_st );
1033        this->video_st = NULL;
1034        if ( this->audio_st ) close_audio( this, NULL, this->audio_st );
1035        this->audio_st = NULL;
1036
1037        if( !( this->fmt->flags & AVFMT_NOFILE ) )  {
1038
1039                if( this->oc ) {
1040
1041                        if( this->oc->pb ) {
1042        // NEWFFMPEG
1043                                /* close the output file */
1044                                avio_close( this->oc->pb );
1045                                this->oc->pb = NULL;
1046                        };
1047                };
1048        }
1049
1050        if ( this->fp_sound_input ) {
1051
1052                fclose( this->fp_sound_input );
1053                this->fp_sound_input = NULL;
1054        }
1055
1056        /* free the context, includes streams */
1057        if( this->oc ) avformat_free_context( this->oc );
1058        this->oc = NULL;
1059    this->video_finished = TRUE; 
1060
1061        /* free sws context */
1062        if( this->img_convert_ctx ) sws_freeContext(this->img_convert_ctx);
1063        this->img_convert_ctx = 0;
1064
1065        /* delete pic queue */
1066    if( this->pictureQueue ) delete this->pictureQueue;
1067        this->pictureQueue = NULL;
1068
1069        if( s_logFile.is_open() ) {
1070
1071                s_logFile << "Cffmpeg_dll::~Cffmpeg_dll() exit." << endl;
1072                // Close the logfile
1073                s_logFile.close();
1074        };
1075
1076        return;
1077}
1078
1079int
1080Cffmpeg_dll::QueuePicture(Picture& pic)
1081{
1082    EnterCriticalSection(&this->queueLock);
1083    this->pictureQueue->push( pic );
1084
1085        if( this->pictureQueue->size() > gstc_u4MaxQueueSize ) gstc_u4MaxQueueSize = this->pictureQueue->size();
1086
1087    LeaveCriticalSection(&this->queueLock);
1088    return 0;
1089}
1090
1091DWORD WINAPI
1092Cffmpeg_dll_thread(LPVOID param)
1093{
1094    Cffmpeg_dll *ptr = (Cffmpeg_dll *)param;
1095    bool done = false;
1096    do {
1097        EnterCriticalSection(&ptr->queueLock);
1098
1099        while(!ptr->pictureQueue->empty()) 
1100        {
1101            Picture& pic = ptr->pictureQueue->front();
1102            ptr->pictureQueue->pop();
1103            EncodePictureReal_ffmpeg_dll(ptr, pic.frame, pic.pic, pic.pic_size, pic.vStart, pic.soundOffset, pic.lStart, pic.lEnd, pic.vEnd);
1104
1105                        if( pic.bFree ) free( pic.pic );
1106
1107            if (pic.vEnd <= pic.frame)
1108            {
1109                av_log(ptr->oc, AV_LOG_ERROR, "encoded all frames\n");
1110                done = true;
1111            }
1112        } 
1113        LeaveCriticalSection(&ptr->queueLock);
1114        Sleep(1);
1115    } while(!done);
1116    return 0;
1117}