36#include "libavutil/opt.h"
37#include "libavutil/samplefmt.h"
38#include "libavutil/imgutils.h"
41#define LOC QString("AVFW(%1): ").arg(m_filename)
42#define LOC_ERR QString("AVFW(%1) Error: ").arg(m_filename)
43#define LOC_WARN QString("AVFW(%1) Warning: ").arg(m_filename)
59 const AVOutputFormat *fmt = av_guess_format(
m_container.toLatin1().constData(),
nullptr,
nullptr);
62 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Init(): Unable to guess AVOutputFormat from container %1")
74 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Init(): Unable to find video codec %1")
82 m_fmt.video_codec = AV_CODEC_ID_NONE;
88 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Init(): Unable to find audio codec %1")
95 m_ctx = avformat_alloc_context();
98 LOG(VB_RECORD, LOG_ERR,
LOC +
"Init(): Unable to allocate AVFormatContext");
105 m_ctx->packet_size = 2324;
108 auto size =
static_cast<size_t>(
filename.size());
109 m_ctx->url =
static_cast<char*
>(av_malloc(size));
112 if (
m_fmt.video_codec != AV_CODEC_ID_NONE)
114 if (
m_fmt.audio_codec != AV_CODEC_ID_NONE)
119 LOG(VB_RECORD, LOG_ERR,
LOC +
"Init(): OpenVideo() failed");
125 LOG(VB_RECORD, LOG_ERR,
LOC +
"Init(): OpenAudio() failed");
149 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"OpenFile(): RingBuffer::Create() failed: '%1'")
157 if (!(
m_fmt.flags & AVFMT_NOFILE))
161 if (
m_ctx->pb ==
nullptr)
163 LOG(VB_RECORD, LOG_ERR,
LOC +
"OpenFile(): failed to allocate AVIOContext");
168 if (avformat_write_header(
m_ctx,
nullptr) < 0)
188 av_write_trailer(
m_ctx);
192 for(
uint i = 0; i <
m_ctx->nb_streams; i++)
193 av_freep(
reinterpret_cast<void*
>(&
m_ctx->streams[i]));
194 av_freep(
reinterpret_cast<void*
>(&
m_ctx));
217 AVPacket *pkt = av_packet_alloc();
220 LOG(VB_RECORD, LOG_ERR,
"packet allocation failed");
221 return AVERROR(ENOMEM);
230 bool got_packet =
false;
231 int ret = avcodec_receive_packet(avctx, pkt);
234 if (ret == AVERROR(EAGAIN))
237 ret = avcodec_send_frame(avctx,
m_picture);
245 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"video encode error: %1 (%2)")
247 av_packet_free(&pkt);
253 av_packet_free(&pkt);
257 std::chrono::milliseconds tc =
Frame->m_timecode;
265 if (pict_type == AV_PICTURE_TYPE_I)
266 pkt->flags |= AV_PKT_FLAG_KEY;
274 pkt->dts = AV_NOPTS_VALUE;
277 ret = av_interleaved_write_frame(
m_ctx, pkt);
279 LOG(VB_RECORD, LOG_ERR,
LOC +
"WriteVideoFrame(): av_interleaved_write_frame couldn't write Video");
283 av_packet_unref(pkt);
284 av_packet_free(&pkt);
290#if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
293 buf16[i] = qFromLittleEndian<quint16>(buf16[i]);
302 AVPacket *pkt = av_packet_alloc();
305 LOG(VB_RECORD, LOG_ERR,
"packet allocation failed");
306 return AVERROR(ENOMEM);
309 if (av_get_packed_sample_fmt(avctx->sample_fmt) == AV_SAMPLE_FMT_FLT)
312 static_cast<void*
>(
Buffer), samples_per_avframe * sampleSizeIn);
315 if (av_sample_fmt_is_planar(avctx->sample_fmt))
319 samples_per_avframe * sampleSizeOut);
340 bool got_packet =
false;
341 int ret = avcodec_receive_packet(avctx, pkt);
344 if (ret == AVERROR(EAGAIN))
355 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"audio encode error: %1 (%2)")
357 av_packet_free(&pkt);
363 av_packet_free(&pkt);
367 std::chrono::milliseconds tc = Timecode;
381 pkt->dts = AV_NOPTS_VALUE;
382 pkt->flags |= AV_PKT_FLAG_KEY;
385 ret = av_interleaved_write_frame(
m_ctx, pkt);
387 LOG(VB_RECORD, LOG_ERR,
LOC +
"WriteAudioFrame(): av_interleaved_write_frame couldn't write Audio");
390 av_packet_unref(pkt);
391 av_packet_free(&pkt);
396 std::chrono::milliseconds ,
int )
421 AVStream *stream = avformat_new_stream(
m_ctx,
nullptr);
424 LOG(VB_RECORD, LOG_ERR,
LOC +
"AddVideoStream(): avformat_new_stream() failed");
429 stream->time_base.den = 90000;
430 stream->time_base.num = 1;
431 stream->r_frame_rate.num = 0;
432 stream->r_frame_rate.den = 0;
434 const AVCodec *codec = avcodec_find_encoder(
m_ctx->oformat->video_codec);
437 LOG(VB_RECORD, LOG_ERR,
LOC +
"AddVideoStream(): avcodec_find_encoder() failed");
443 context->codec = codec;
444 context->codec_id =
m_ctx->oformat->video_codec;
445 context->codec_type = AVMEDIA_TYPE_VIDEO;
455 context->pix_fmt = AV_PIX_FMT_YUV420P;
457 context->thread_type = FF_THREAD_SLICE;
459 if (context->codec_id == AV_CODEC_ID_MPEG2VIDEO)
461 context->max_b_frames = 2;
463 else if (context->codec_id == AV_CODEC_ID_MPEG1VIDEO)
465 context->mb_decision = 2;
467 else if (context->codec_id == AV_CODEC_ID_H264)
473 if ((context->height > 720) ||
474 (context->bit_rate > 1400000))
478 av_opt_set(context->priv_data,
"profile",
"main", 0);
480 else if ((context->height > 576) ||
481 (context->bit_rate > 1000000))
485 av_opt_set(context->priv_data,
"profile",
"baseline", 0);
491 av_opt_set(context->priv_data,
"profile",
"baseline", 0);
495 context->max_b_frames = 0;
497 context->flags |= AV_CODEC_FLAG_LOOP_FILTER;
498 context->me_cmp |= 1;
501 av_opt_set(context,
"me_method",
"hex", 0);
502 context->me_subpel_quality = 6;
503 context->me_range = 16;
504 context->keyint_min = 25;
506 av_opt_set_int(context,
"sc_threshold", 40, 0);
507 context->i_quant_factor = 0.71F;
509 av_opt_set_int(context,
"b_strategy", 1, 0);
510 context->qcompress = 0.6F;
513 context->max_qdiff = 4;
515 context->trellis = 0;
518 av_opt_set(context,
"partitions",
"i8x8,i4x4,p8x8,b8x8", 0);
519 av_opt_set_int(context,
"direct-pred", 1, 0);
520 av_opt_set_int(context,
"rc-lookahead", 0, 0);
521 av_opt_set_int(context,
"fast-pskip", 1, 0);
522 av_opt_set_int(context,
"mixed-refs", 1, 0);
523 av_opt_set_int(context,
"8x8dct", 0, 0);
524 av_opt_set_int(context,
"weightb", 0, 0);
527 av_opt_set(context->priv_data,
"preset",
m_encodingPreset.toLatin1().constData(), 0);
528 av_opt_set(context->priv_data,
"tune",
m_encodingTune.toLatin1().constData(), 0);
531 if(
m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
532 context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
543 if (avcodec_open2(context,
nullptr,
nullptr) < 0)
545 LOG(VB_RECORD, LOG_ERR,
LOC +
"OpenVideo(): avcodec_open() failed");
554 LOG(VB_RECORD, LOG_ERR,
LOC +
"OpenVideo(): AllocPicture() failed");
568 AVStream *stream = avformat_new_stream(
m_ctx,
nullptr);
571 LOG(VB_RECORD, LOG_ERR,
LOC +
"AddAudioStream(): avformat_new_stream() failed");
578 context->codec_id =
m_ctx->oformat->audio_codec;
579 context->codec_type = AVMEDIA_TYPE_AUDIO;
590 stream->time_base.den = 90000;
591 stream->time_base.num = 1;
594 if (
m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
595 context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
602 const AVSampleFormat *sample_fmts =
nullptr;
603 int out_num_configs = 0;
604 int ret = avcodec_get_supported_config(
nullptr, Codec, AV_CODEC_CONFIG_SAMPLE_FORMAT,
605 0, (
const void **) &sample_fmts, &out_num_configs);
611 for (
int i = 0; i < out_num_configs; i++)
613 if (av_get_packed_sample_fmt(sample_fmts[i]) ==
Format)
615 Ctx->sample_fmt = sample_fmts[i];
626 context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
628 const AVCodec *codec = avcodec_find_encoder(context->codec_id);
631 LOG(VB_RECORD, LOG_ERR,
LOC +
"OpenAudio(): avcodec_find_encoder() failed");
641 if (avcodec_open2(context, codec,
nullptr) < 0)
643 LOG(VB_RECORD, LOG_ERR,
LOC +
"OpenAudio(): avcodec_open() failed");
652 LOG(VB_RECORD, LOG_ERR,
LOC +
"OpenAudio(): alloc_frame() failed");
657 av_get_bytes_per_sample(context->sample_fmt);
658 if (av_get_packed_sample_fmt(context->sample_fmt) == AV_SAMPLE_FMT_FLT)
661 m_audioInBuf =
static_cast<unsigned char*
>(av_malloc(size));
666 if (av_sample_fmt_is_planar(context->sample_fmt))
669 m_audioInPBuf =
static_cast<unsigned char*
>(av_malloc(size));
678 AVFrame *picture = av_frame_alloc();
681 LOG(VB_RECORD, LOG_ERR,
LOC +
"AllocPicture failed");
685 int size = av_image_get_buffer_size(PixFmt,
m_width,
m_height, IMAGE_ALIGN);
686 auto *buffer =
static_cast<unsigned char*
>(av_malloc(
static_cast<size_t>(size)));
689 LOG(VB_RECORD, LOG_ERR,
LOC +
"AllocPicture(): av_malloc() failed");
690 av_frame_free(&picture);
694 av_image_fill_arrays(picture->data, picture->linesize, buffer, PixFmt,
m_width,
m_height, IMAGE_ALIGN);
701 result.den =
static_cast<int>(floor(
m_frameRate * 100));
706 const AVRational *supported_framerates =
nullptr;
707 int out_num_configs = 0;
708 int ret = avcodec_get_supported_config(
nullptr,
m_avVideoCodec, AV_CODEC_CONFIG_FRAME_RATE,
709 0, (
const void **) &supported_framerates, &out_num_configs);
712 const AVRational *best =
nullptr;
713 AVRational best_error = { INT_MAX, 1 };
714 for (
int i = 0; i < out_num_configs; i++)
716 AVRational
error = av_sub_q(result, supported_framerates[i]);
719 if (av_cmp_q(
error, best_error) < 0)
722 best = supported_framerates + i;
726 if (best && best->num && best->den)
728 result.den = best->num;
729 result.num = best->den;
734 if (result.den == 2997)
739 else if (result.den == 5994)
static int SampleSize(AudioFormat format)
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
static void DeinterleaveSamples(AudioFormat format, int channels, uint8_t *output, const uint8_t *input, int data_size)
Deinterleave input samples Deinterleave audio samples and compact them.
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
static int FillAVFrame(AVFrame *Frame, const MythVideoFrame *From, AVPixelFormat Fmt=AV_PIX_FMT_NONE)
Initialise AVFrame with content from MythVideoFrame.
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
void FreeCodecContext(const AVStream *Stream)
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)