75 va_end(VaArgs); |
75 va_end(VaArgs); |
76 |
76 |
77 AddFileLogRaw("Error in av-wrapper: "); |
77 AddFileLogRaw("Error in av-wrapper: "); |
78 AddFileLogRaw(Buffer); |
78 AddFileLogRaw(Buffer); |
79 AddFileLogRaw("\n"); |
79 AddFileLogRaw("\n"); |
80 exit(1); |
80 return(-1); |
81 } |
81 } |
82 |
82 |
83 // Function to be called from libav for logging. |
83 // Function to be called from libav for logging. |
84 // Note: libav can call LogCallback from different threads |
84 // Note: libav can call LogCallback from different threads |
85 // (there is mutex in AddFileLogRaw). |
85 // (there is mutex in AddFileLogRaw). |
208 #endif |
208 #endif |
209 |
209 |
210 // Write the compressed frame to the media file. |
210 // Write the compressed frame to the media file. |
211 Packet.stream_index = g_pAStream->index; |
211 Packet.stream_index = g_pAStream->index; |
212 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
212 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
213 FatalError("Error while writing audio frame"); |
213 return FatalError("Error while writing audio frame"); |
214 return 1; |
214 return 1; |
215 } |
215 } |
216 |
216 |
217 // add a video output stream |
217 // add a video output stream |
218 static void AddVideoStream() |
218 static int AddVideoStream() |
219 { |
219 { |
220 #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
220 #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
221 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); |
221 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); |
222 #else |
222 #else |
223 g_pVStream = av_new_stream(g_pContainer, 0); |
223 g_pVStream = av_new_stream(g_pContainer, 0); |
224 #endif |
224 #endif |
225 if (!g_pVStream) |
225 if (!g_pVStream) |
226 FatalError("Could not allocate video stream"); |
226 return FatalError("Could not allocate video stream"); |
227 |
227 |
228 g_pVideo = g_pVStream->codec; |
228 g_pVideo = g_pVStream->codec; |
229 |
229 |
230 avcodec_get_context_defaults3(g_pVideo, g_pVCodec); |
230 avcodec_get_context_defaults3(g_pVideo, g_pVCodec); |
231 g_pVideo->codec_id = g_pVCodec->id; |
231 g_pVideo->codec_id = g_pVCodec->id; |
295 |
295 |
296 if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) |
296 if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) |
297 #else |
297 #else |
298 if (avcodec_open(g_pVideo, g_pVCodec) < 0) |
298 if (avcodec_open(g_pVideo, g_pVCodec) < 0) |
299 #endif |
299 #endif |
300 FatalError("Could not open video codec %s", g_pVCodec->long_name); |
300 return FatalError("Could not open video codec %s", g_pVCodec->long_name); |
301 |
301 |
302 g_pVFrame = avcodec_alloc_frame(); |
302 g_pVFrame = avcodec_alloc_frame(); |
303 if (!g_pVFrame) |
303 if (!g_pVFrame) |
304 FatalError("Could not allocate frame"); |
304 return FatalError("Could not allocate frame"); |
305 |
305 |
306 g_pVFrame->linesize[0] = g_Width; |
306 g_pVFrame->linesize[0] = g_Width; |
307 g_pVFrame->linesize[1] = g_Width/2; |
307 g_pVFrame->linesize[1] = g_Width/2; |
308 g_pVFrame->linesize[2] = g_Width/2; |
308 g_pVFrame->linesize[2] = g_Width/2; |
309 g_pVFrame->linesize[3] = 0; |
309 g_pVFrame->linesize[3] = 0; |
|
310 return 0; |
310 } |
311 } |
311 |
312 |
312 static int WriteFrame(AVFrame* pFrame) |
313 static int WriteFrame(AVFrame* pFrame) |
313 { |
314 { |
314 double AudioTime, VideoTime; |
315 double AudioTime, VideoTime; |
315 |
316 int ret; |
316 // write interleaved audio frame |
317 // write interleaved audio frame |
317 if (g_pAStream) |
318 if (g_pAStream) |
318 { |
319 { |
319 VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den; |
320 VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den; |
320 do |
321 do |
|
322 { |
321 AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den; |
323 AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den; |
322 while (AudioTime < VideoTime && WriteAudioFrame()); |
324 ret = WriteAudioFrame(); |
|
325 } |
|
326 while (AudioTime < VideoTime && ret); |
|
327 if (ret < 0) |
|
328 return ret; |
323 } |
329 } |
324 |
330 |
325 if (!g_pVStream) |
331 if (!g_pVStream) |
326 return 0; |
332 return 0; |
327 |
333 |
339 Packet.stream_index = g_pVStream->index; |
345 Packet.stream_index = g_pVStream->index; |
340 Packet.data = (uint8_t*)pFrame; |
346 Packet.data = (uint8_t*)pFrame; |
341 Packet.size = sizeof(AVPicture); |
347 Packet.size = sizeof(AVPicture); |
342 |
348 |
343 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
349 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
344 FatalError("Error while writing video frame"); |
350 return FatalError("Error while writing video frame"); |
345 return 0; |
351 return 0; |
346 } |
352 } |
347 else |
353 else |
348 { |
354 { |
349 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
355 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
350 int got_packet; |
356 int got_packet; |
351 if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0) |
357 if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0) |
352 FatalError("avcodec_encode_video2 failed"); |
358 return FatalError("avcodec_encode_video2 failed"); |
353 if (!got_packet) |
359 if (!got_packet) |
354 return 0; |
360 return 0; |
355 |
361 |
356 if (Packet.pts != AV_NOPTS_VALUE) |
362 if (Packet.pts != AV_NOPTS_VALUE) |
357 Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base); |
363 Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base); |
358 if (Packet.dts != AV_NOPTS_VALUE) |
364 if (Packet.dts != AV_NOPTS_VALUE) |
359 Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base); |
365 Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base); |
360 #else |
366 #else |
361 Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame); |
367 Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame); |
362 if (Packet.size < 0) |
368 if (Packet.size < 0) |
363 FatalError("avcodec_encode_video failed"); |
369 return FatalError("avcodec_encode_video failed"); |
364 if (Packet.size == 0) |
370 if (Packet.size == 0) |
365 return 0; |
371 return 0; |
366 |
372 |
367 if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE) |
373 if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE) |
368 Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base); |
374 Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base); |
371 Packet.data = g_OutBuffer; |
377 Packet.data = g_OutBuffer; |
372 #endif |
378 #endif |
373 // write the compressed frame in the media file |
379 // write the compressed frame in the media file |
374 Packet.stream_index = g_pVStream->index; |
380 Packet.stream_index = g_pVStream->index; |
375 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
381 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
376 FatalError("Error while writing video frame"); |
382 return FatalError("Error while writing video frame"); |
377 |
383 |
378 return 1; |
384 return 1; |
379 } |
385 } |
380 } |
386 } |
381 |
387 |
382 AVWRAP_DECL void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr) |
388 AVWRAP_DECL int AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr) |
383 { |
389 { |
384 g_pVFrame->data[0] = pY; |
390 g_pVFrame->data[0] = pY; |
385 g_pVFrame->data[1] = pCb; |
391 g_pVFrame->data[1] = pCb; |
386 g_pVFrame->data[2] = pCr; |
392 g_pVFrame->data[2] = pCr; |
387 WriteFrame(g_pVFrame); |
393 return WriteFrame(g_pVFrame); |
388 } |
394 } |
389 |
395 |
390 AVWRAP_DECL void AVWrapper_Init( |
396 AVWRAP_DECL int AVWrapper_Init( |
391 void (*pAddFileLogRaw)(const char*), |
397 void (*pAddFileLogRaw)(const char*), |
392 const char* pFilename, |
398 const char* pFilename, |
393 const char* pDesc, |
399 const char* pDesc, |
394 const char* pSoundFile, |
400 const char* pSoundFile, |
395 const char* pFormatName, |
401 const char* pFormatName, |
397 const char* pACodecName, |
403 const char* pACodecName, |
398 int Width, int Height, |
404 int Width, int Height, |
399 int FramerateNum, int FramerateDen, |
405 int FramerateNum, int FramerateDen, |
400 int VQuality) |
406 int VQuality) |
401 { |
407 { |
|
408 int ret; |
402 AddFileLogRaw = pAddFileLogRaw; |
409 AddFileLogRaw = pAddFileLogRaw; |
403 av_log_set_callback( &LogCallback ); |
410 av_log_set_callback( &LogCallback ); |
404 |
411 |
405 g_Width = Width; |
412 g_Width = Width; |
406 g_Height = Height; |
413 g_Height = Height; |
412 av_register_all(); |
419 av_register_all(); |
413 |
420 |
414 // find format |
421 // find format |
415 g_pFormat = av_guess_format(pFormatName, NULL, NULL); |
422 g_pFormat = av_guess_format(pFormatName, NULL, NULL); |
416 if (!g_pFormat) |
423 if (!g_pFormat) |
417 FatalError("Format \"%s\" was not found", pFormatName); |
424 return FatalError("Format \"%s\" was not found", pFormatName); |
418 |
425 |
419 // allocate the output media context |
426 // allocate the output media context |
420 g_pContainer = avformat_alloc_context(); |
427 g_pContainer = avformat_alloc_context(); |
421 if (!g_pContainer) |
428 if (!g_pContainer) |
422 FatalError("Could not allocate output context"); |
429 return FatalError("Could not allocate output context"); |
423 |
430 |
424 g_pContainer->oformat = g_pFormat; |
431 g_pContainer->oformat = g_pFormat; |
425 |
432 |
426 // store description of file |
433 // store description of file |
427 av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0); |
434 av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0); |
460 } |
471 } |
461 else |
472 else |
462 Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName); |
473 Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName); |
463 |
474 |
464 if (!g_pAStream && !g_pVStream) |
475 if (!g_pAStream && !g_pVStream) |
465 FatalError("No video, no audio, aborting..."); |
476 return FatalError("No video, no audio, aborting..."); |
466 |
477 |
467 // write format info to log |
478 // write format info to log |
468 av_dump_format(g_pContainer, 0, g_pContainer->filename, 1); |
479 av_dump_format(g_pContainer, 0, g_pContainer->filename, 1); |
469 |
480 |
470 // open the output file, if needed |
481 // open the output file, if needed |
471 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
482 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
472 { |
483 { |
473 if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0) |
484 if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0) |
474 FatalError("Could not open output file (%s)", g_pContainer->filename); |
485 return FatalError("Could not open output file (%s)", g_pContainer->filename); |
475 } |
486 } |
476 |
487 |
477 // write the stream header, if any |
488 // write the stream header, if any |
478 avformat_write_header(g_pContainer, NULL); |
489 avformat_write_header(g_pContainer, NULL); |
479 |
490 |
480 g_pVFrame->pts = -1; |
491 g_pVFrame->pts = -1; |
481 } |
492 return 0; |
482 |
493 } |
483 AVWRAP_DECL void AVWrapper_Close() |
494 |
484 { |
495 AVWRAP_DECL int AVWrapper_Close() |
|
496 { |
|
497 int ret; |
485 // output buffered frames |
498 // output buffered frames |
486 if (g_pVCodec->capabilities & CODEC_CAP_DELAY) |
499 if (g_pVCodec->capabilities & CODEC_CAP_DELAY) |
487 while( WriteFrame(NULL) ); |
500 { |
|
501 do |
|
502 ret = WriteFrame(NULL); |
|
503 while (ret); |
|
504 if (ret < 0) |
|
505 return ret; |
|
506 } |
488 // output any remaining audio |
507 // output any remaining audio |
489 while( WriteAudioFrame() ); |
508 do |
|
509 { |
|
510 ret = WriteAudioFrame(); |
|
511 } |
|
512 while(ret); |
|
513 if (ret < 0) |
|
514 return ret; |
490 |
515 |
491 // write the trailer, if any. |
516 // write the trailer, if any. |
492 av_write_trailer(g_pContainer); |
517 av_write_trailer(g_pContainer); |
493 |
518 |
494 // close the output file |
519 // close the output file |