Ticket #1548: ffmpeg_dll.cpp

File ffmpeg_dll.cpp, 30.0 KB (added by TheSHEEEP, 14 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}