15 static AVCodec* g_pVCodec; |
16 static AVCodec* g_pVCodec; |
16 static AVCodecContext* g_pAudio; |
17 static AVCodecContext* g_pAudio; |
17 static AVCodecContext* g_pVideo; |
18 static AVCodecContext* g_pVideo; |
18 |
19 |
19 static int g_Width, g_Height; |
20 static int g_Width, g_Height; |
20 static int g_Frequency, g_Channels; |
21 static uint32_t g_Frequency, g_Channels; |
21 static int g_VQuality, g_AQuality; |
22 static int g_VQuality, g_AQuality; |
22 static AVRational g_Framerate; |
23 static AVRational g_Framerate; |
23 static const char* g_pPreset; |
24 static const char* g_pPreset; |
24 |
25 |
25 static FILE* g_pSoundFile; |
26 static FILE* g_pSoundFile; |
26 static int16_t* g_pSamples; |
27 static int16_t* g_pSamples; |
27 static int g_NumSamples; |
28 static int g_NumSamples; |
28 |
|
29 static char g_Filename[1024]; |
|
30 |
29 |
31 /* |
30 /* |
32 Initially I wrote code for latest ffmpeg, but on Linux (Ubuntu) |
31 Initially I wrote code for latest ffmpeg, but on Linux (Ubuntu) |
33 only older version is available from repository. That's why you see here |
32 only older version is available from repository. That's why you see here |
34 all of this #if LIBAVCODEC_VERSION_MAJOR < 54. |
33 all of this #if LIBAVCODEC_VERSION_MAJOR < 54. |
88 g_pAStream = avformat_new_stream(g_pContainer, g_pACodec); |
87 g_pAStream = avformat_new_stream(g_pContainer, g_pACodec); |
89 #else |
88 #else |
90 g_pAStream = av_new_stream(g_pContainer, 1); |
89 g_pAStream = av_new_stream(g_pContainer, 1); |
91 #endif |
90 #endif |
92 if(!g_pAStream) |
91 if(!g_pAStream) |
93 FatalError("Could not allocate audio stream"); |
92 { |
|
93 Log("Could not allocate audio stream"); |
|
94 return; |
|
95 } |
94 g_pAStream->id = 1; |
96 g_pAStream->id = 1; |
95 |
97 |
96 g_pAudio = g_pAStream->codec; |
98 g_pAudio = g_pAStream->codec; |
97 |
99 |
98 avcodec_get_context_defaults3(g_pAudio, g_pACodec); |
100 avcodec_get_context_defaults3(g_pAudio, g_pACodec); |
116 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
118 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
117 g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER; |
119 g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER; |
118 |
120 |
119 // open it |
121 // open it |
120 if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0) |
122 if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0) |
121 FatalError("Could not open audio codec %s", g_pACodec->long_name); |
123 { |
|
124 Log("Could not open audio codec %s", g_pACodec->long_name); |
|
125 return; |
|
126 } |
122 |
127 |
123 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
128 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
124 if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) |
129 if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) |
125 #else |
130 #else |
126 if (g_pAudio->frame_size == 0) |
131 if (g_pAudio->frame_size == 0) |
129 else |
134 else |
130 g_NumSamples = g_pAudio->frame_size; |
135 g_NumSamples = g_pAudio->frame_size; |
131 g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t)); |
136 g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t)); |
132 g_pAFrame = avcodec_alloc_frame(); |
137 g_pAFrame = avcodec_alloc_frame(); |
133 if (!g_pAFrame) |
138 if (!g_pAFrame) |
134 FatalError("Could not allocate frame"); |
139 { |
|
140 Log("Could not allocate frame"); |
|
141 return; |
|
142 } |
135 } |
143 } |
136 |
144 |
137 // returns non-zero if there is more sound |
145 // returns non-zero if there is more sound |
138 static int WriteAudioFrame() |
146 static int WriteAudioFrame() |
139 { |
147 { |
240 g_pVFrame->linesize[1] = g_Width/2; |
248 g_pVFrame->linesize[1] = g_Width/2; |
241 g_pVFrame->linesize[2] = g_Width/2; |
249 g_pVFrame->linesize[2] = g_Width/2; |
242 g_pVFrame->linesize[3] = 0; |
250 g_pVFrame->linesize[3] = 0; |
243 } |
251 } |
244 |
252 |
245 static int WriteFrame( AVFrame* pFrame ) |
253 static int WriteFrame(AVFrame* pFrame) |
246 { |
254 { |
247 double AudioTime, VideoTime; |
255 double AudioTime, VideoTime; |
248 |
256 |
249 // write interleaved audio frame |
257 // write interleaved audio frame |
250 if (g_pAStream) |
258 if (g_pAStream) |
321 } |
329 } |
322 |
330 |
323 void AVWrapper_Init( |
331 void AVWrapper_Init( |
324 void (*pAddFileLogRaw)(const char*), |
332 void (*pAddFileLogRaw)(const char*), |
325 const char* pFilename, |
333 const char* pFilename, |
326 const char* pFinalFilename, |
334 const char* pDesc, |
327 const char* pSoundFile, |
335 const char* pSoundFile, |
328 const char* pFormatName, |
336 const char* pFormatName, |
329 const char* pVCodecName, |
337 const char* pVCodecName, |
330 const char* pACodecName, |
338 const char* pACodecName, |
331 const char* pVPreset, |
339 const char* pVPreset, |
332 int Width, int Height, |
340 int Width, int Height, |
333 int FramerateNum, int FramerateDen, |
341 int FramerateNum, int FramerateDen, |
334 int Frequency, int Channels, |
|
335 int VQuality, int AQuality) |
342 int VQuality, int AQuality) |
336 { |
343 { |
337 AddFileLogRaw = pAddFileLogRaw; |
344 AddFileLogRaw = pAddFileLogRaw; |
338 av_log_set_callback( &LogCallback ); |
345 av_log_set_callback( &LogCallback ); |
339 |
346 |
340 g_Width = Width; |
347 g_Width = Width & ~1; // make even (dimensions should be even) |
341 g_Height = Height; |
348 g_Height = Height & ~1; // make even |
342 g_Framerate.num = FramerateNum; |
349 g_Framerate.num = FramerateNum; |
343 g_Framerate.den = FramerateDen; |
350 g_Framerate.den = FramerateDen; |
344 g_Frequency = Frequency; |
|
345 g_Channels = Channels; |
|
346 g_VQuality = VQuality; |
351 g_VQuality = VQuality; |
347 g_AQuality = AQuality; |
352 g_AQuality = AQuality; |
348 g_pPreset = pVPreset; |
353 g_pPreset = pVPreset; |
349 |
354 |
350 // initialize libav and register all codecs and formats |
355 // initialize libav and register all codecs and formats |
359 g_pContainer = avformat_alloc_context(); |
364 g_pContainer = avformat_alloc_context(); |
360 if (!g_pContainer) |
365 if (!g_pContainer) |
361 FatalError("Could not allocate output context"); |
366 FatalError("Could not allocate output context"); |
362 |
367 |
363 g_pContainer->oformat = g_pFormat; |
368 g_pContainer->oformat = g_pFormat; |
|
369 |
|
370 // store description of file |
|
371 av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0); |
364 |
372 |
365 // append extesnion to filename |
373 // append extesnion to filename |
366 char ext[16]; |
374 char ext[16]; |
367 strncpy(ext, g_pFormat->extensions, 16); |
375 strncpy(ext, g_pFormat->extensions, 16); |
368 ext[15] = 0; |
376 ext[15] = 0; |
369 ext[strcspn(ext,",")] = 0; |
377 ext[strcspn(ext,",")] = 0; |
370 snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext); |
378 snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext); |
371 snprintf(g_Filename, sizeof(g_Filename), "%s.%s", pFinalFilename, ext); |
|
372 |
379 |
373 // find codecs |
380 // find codecs |
374 g_pVCodec = avcodec_find_encoder_by_name(pVCodecName); |
381 g_pVCodec = avcodec_find_encoder_by_name(pVCodecName); |
375 g_pACodec = avcodec_find_encoder_by_name(pACodecName); |
382 g_pACodec = avcodec_find_encoder_by_name(pACodecName); |
376 |
383 |
382 AddVideoStream(); |
389 AddVideoStream(); |
383 else |
390 else |
384 Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName); |
391 Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName); |
385 |
392 |
386 if (g_pACodec) |
393 if (g_pACodec) |
387 AddAudioStream(); |
394 { |
|
395 g_pSoundFile = fopen(pSoundFile, "rb"); |
|
396 if (g_pSoundFile) |
|
397 { |
|
398 fread(&g_Frequency, 4, 1, g_pSoundFile); |
|
399 fread(&g_Channels, 4, 1, g_pSoundFile); |
|
400 AddAudioStream(); |
|
401 } |
|
402 else |
|
403 Log("Could not open %s", pSoundFile); |
|
404 } |
388 else |
405 else |
389 Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName); |
406 Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName); |
390 |
407 |
391 if (!g_pAStream && !g_pVStream) |
408 if (!g_pAStream && !g_pVStream) |
392 FatalError("No video, no audio, aborting..."); |
409 FatalError("No video, no audio, aborting..."); |
393 |
|
394 if (g_pAStream) |
|
395 { |
|
396 g_pSoundFile = fopen(pSoundFile, "rb"); |
|
397 if (!g_pSoundFile) |
|
398 FatalError("Could not open %s", pSoundFile); |
|
399 } |
|
400 |
410 |
401 // write format info to log |
411 // write format info to log |
402 av_dump_format(g_pContainer, 0, g_pContainer->filename, 1); |
412 av_dump_format(g_pContainer, 0, g_pContainer->filename, 1); |
403 |
413 |
404 // open the output file, if needed |
414 // open the output file, if needed |
426 av_write_trailer(g_pContainer); |
436 av_write_trailer(g_pContainer); |
427 |
437 |
428 // close the output file |
438 // close the output file |
429 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
439 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
430 avio_close(g_pContainer->pb); |
440 avio_close(g_pContainer->pb); |
431 |
|
432 // move file to destination |
|
433 rename(g_pContainer->filename, g_Filename); |
|
434 |
441 |
435 // free everything |
442 // free everything |
436 if (g_pVStream) |
443 if (g_pVStream) |
437 { |
444 { |
438 avcodec_close(g_pVideo); |
445 avcodec_close(g_pVideo); |