MythTV master
mythavformatwriter.cpp
Go to the documentation of this file.
1/*
2 * Class AVFormatWriter
3 *
4 * Copyright (C) Chris Pinkham 2011
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
21
22#include <limits> // workaround QTBUG-90395
23
24#include <QtGlobal>
25#include <QtEndian>
26
27// MythTV
28#include "libmythbase/mythconfig.h"
32#include "mythavutil.h"
33
34
35// FFmpeg
36extern "C" {
37#include "libavutil/opt.h"
38#include "libavutil/samplefmt.h"
39#include "libavutil/imgutils.h"
40}
41
42#define LOC QString("AVFW(%1): ").arg(m_filename)
43#define LOC_ERR QString("AVFW(%1) Error: ").arg(m_filename)
44#define LOC_WARN QString("AVFW(%1) Warning: ").arg(m_filename)
45
47{
49
50 av_freep(reinterpret_cast<void*>(&m_audioInBuf));
51 av_freep(reinterpret_cast<void*>(&m_audioInPBuf));
52 if (m_audPicture)
53 av_frame_free(&m_audPicture);
54 Cleanup();
55 av_frame_free(&m_picture);
56}
57
59{
60 const AVOutputFormat *fmt = av_guess_format(m_container.toLatin1().constData(), nullptr, nullptr);
61 if (!fmt)
62 {
63 LOG(VB_RECORD, LOG_ERR, LOC + QString("Init(): Unable to guess AVOutputFormat from container %1")
64 .arg(m_container));
65 return false;
66 }
67
68 m_fmt = *fmt;
69
70 if (m_width && m_height)
71 {
72 m_avVideoCodec = avcodec_find_encoder_by_name(m_videoCodec.toLatin1().constData());
73 if (!m_avVideoCodec)
74 {
75 LOG(VB_RECORD, LOG_ERR, LOC + QString("Init(): Unable to find video codec %1")
76 .arg(m_videoCodec));
77 return false;
78 }
79 m_fmt.video_codec = m_avVideoCodec->id;
80 }
81 else
82 {
83 m_fmt.video_codec = AV_CODEC_ID_NONE;
84 }
85
86 m_avAudioCodec = avcodec_find_encoder_by_name(m_audioCodec.toLatin1().constData());
87 if (!m_avAudioCodec)
88 {
89 LOG(VB_RECORD, LOG_ERR, LOC + QString("Init(): Unable to find audio codec %1")
90 .arg(m_audioCodec));
91 return false;
92 }
93
94 m_fmt.audio_codec = m_avAudioCodec->id;
95
96 m_ctx = avformat_alloc_context();
97 if (!m_ctx)
98 {
99 LOG(VB_RECORD, LOG_ERR, LOC + "Init(): Unable to allocate AVFormatContext");
100 return false;
101 }
102
103 m_ctx->oformat = &m_fmt;
104
105 if (m_container == "mpegts")
106 m_ctx->packet_size = 2324;
107
108 QByteArray filename = m_filename.toLatin1();
109 auto size = static_cast<size_t>(filename.size());
110 m_ctx->url = static_cast<char*>(av_malloc(size));
111 memcpy(m_ctx->url, filename.constData(), size);
112
113 if (m_fmt.video_codec != AV_CODEC_ID_NONE)
115 if (m_fmt.audio_codec != AV_CODEC_ID_NONE)
117
118 if (m_videoStream && !OpenVideo())
119 {
120 LOG(VB_RECORD, LOG_ERR, LOC + "Init(): OpenVideo() failed");
121 return false;
122 }
123
124 if (m_audioStream && !OpenAudio())
125 {
126 LOG(VB_RECORD, LOG_ERR, LOC + "Init(): OpenAudio() failed");
127 return false;
128 }
129
130 return true;
131}
132
134{
135 bool success = openFileHelper();
136 if (!success)
137 {
138 Cleanup();
139 }
140 return success;
141}
142
144{
145 delete m_buffer;
147
148 if (!m_buffer || !m_buffer->GetLastError().isEmpty())
149 {
150 LOG(VB_RECORD, LOG_ERR, LOC + QString("OpenFile(): RingBuffer::Create() failed: '%1'")
151 .arg(m_buffer ? m_buffer->GetLastError() : ""));
152 return false;
153 }
154
155 delete m_avfBuffer;
156 m_avfBuffer = nullptr;
157 m_ctx->pb = nullptr;
158 if (!(m_fmt.flags & AVFMT_NOFILE))
159 {
160 m_avfBuffer = new MythAVFormatBuffer(m_buffer, true, true);
162 if (m_ctx->pb == nullptr)
163 {
164 LOG(VB_RECORD, LOG_ERR, LOC + "OpenFile(): failed to allocate AVIOContext");
165 return false;
166 }
167 }
168
169 if (avformat_write_header(m_ctx, nullptr) < 0)
170 {
171 return false;
172 }
173
174 return true;
175}
176
178{
179 delete m_avfBuffer;
180 m_avfBuffer = nullptr;
181 delete m_buffer;
182 m_buffer = nullptr;
183}
184
186{
187 if (m_ctx)
188 {
189 av_write_trailer(m_ctx);
190 delete m_avfBuffer;
191 m_avfBuffer = nullptr;
192 m_ctx->pb = nullptr;
193 for(uint i = 0; i < m_ctx->nb_streams; i++)
194 av_freep(reinterpret_cast<void*>(&m_ctx->streams[i]));
195 av_freep(reinterpret_cast<void*>(&m_ctx));
196 }
197 return true;
198}
199
201{
202 return (m_bufferedVideoFrameTypes.isEmpty()) ||
203 (m_bufferedVideoFrameTypes.first() == AV_PICTURE_TYPE_I);
204}
205
207{
208 long long framesEncoded = m_framesWritten + m_bufferedVideoFrameTimes.size();
209
210 av_frame_unref(m_picture);
212 m_picture->pts = framesEncoded + 1;
213 m_picture->pict_type = ((framesEncoded % m_keyFrameDist) == 0) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_NONE;
214
215 m_bufferedVideoFrameTimes.push_back(Frame->m_timecode);
216 m_bufferedVideoFrameTypes.push_back(m_picture->pict_type);
217
218 AVPacket *pkt = av_packet_alloc();
219 if (pkt == nullptr)
220 {
221 LOG(VB_RECORD, LOG_ERR, "packet allocation failed");
222 return AVERROR(ENOMEM);
223 }
224
225 AVCodecContext *avctx = m_codecMap.GetCodecContext(m_videoStream);
226
227 // SUGGESTION
228 // Now that avcodec_encode_video2 is removed and replaced
229 // by 2 calls, this could be optimized
230 // into separate routines or separate threads.
231 bool got_packet = false;
232 int ret = avcodec_receive_packet(avctx, pkt);
233 if (ret == 0)
234 got_packet = true;
235 if (ret == AVERROR(EAGAIN))
236 ret = 0;
237 if (ret == 0)
238 ret = avcodec_send_frame(avctx, m_picture);
239 // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
240 // there are 2 packets to be received while only 1 frame to be
241 // sent. The code does not cater for this. Hopefully it will not happen.
242
243 if (ret < 0)
244 {
245 std::string error;
246 LOG(VB_GENERAL, LOG_ERR, LOC + QString("video encode error: %1 (%2)")
247 .arg(av_make_error_stdstring(error, ret)).arg(got_packet));
248 av_packet_free(&pkt);
249 return ret;
250 }
251
252 if (!got_packet)
253 {
254 av_packet_free(&pkt);
255 return ret;
256 }
257
258 std::chrono::milliseconds tc = Frame->m_timecode;
259
260 if (!m_bufferedVideoFrameTimes.isEmpty())
261 tc = m_bufferedVideoFrameTimes.takeFirst();
262
263 if (!m_bufferedVideoFrameTypes.isEmpty())
264 {
265 int pict_type = m_bufferedVideoFrameTypes.takeFirst();
266 if (pict_type == AV_PICTURE_TYPE_I)
267 pkt->flags |= AV_PKT_FLAG_KEY;
268 }
269
270 if (m_startingTimecodeOffset == -1ms)
271 m_startingTimecodeOffset = tc - 1ms;
273
274 pkt->pts = tc.count() * m_videoStream->time_base.den / m_videoStream->time_base.num / 1000;
275 pkt->dts = AV_NOPTS_VALUE;
276 pkt->stream_index= m_videoStream->index;
277
278 ret = av_interleaved_write_frame(m_ctx, pkt);
279 if (ret != 0)
280 LOG(VB_RECORD, LOG_ERR, LOC + "WriteVideoFrame(): av_interleaved_write_frame couldn't write Video");
281
282 Frame->m_timecode = tc + m_startingTimecodeOffset;
284 av_packet_unref(pkt);
285 av_packet_free(&pkt);
286 return 1;
287}
288
289int MythAVFormatWriter::WriteAudioFrame(unsigned char *Buffer, int /*FrameNumber*/, std::chrono::milliseconds &Timecode)
290{
291#if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
292 auto buf16 = reinterpret_cast<uint16_t *>(Buffer);
293 for (int i = 0; i < m_audioChannels * m_audioFrameSize; i++)
294 buf16[i] = qFromLittleEndian<quint16>(buf16[i]);
295#endif
296
297 AVCodecContext *avctx = m_codecMap.GetCodecContext(m_audioStream);
298 int samples_per_avframe = m_audioFrameSize * m_audioChannels;
301 int sampleSizeOut = AudioOutputSettings::SampleSize(format);
302
303 AVPacket *pkt = av_packet_alloc();
304 if (pkt == nullptr)
305 {
306 LOG(VB_RECORD, LOG_ERR, "packet allocation failed");
307 return AVERROR(ENOMEM);
308 }
309
310 if (av_get_packed_sample_fmt(avctx->sample_fmt) == AV_SAMPLE_FMT_FLT)
311 {
312 AudioConvert::toFloat(FORMAT_S16, static_cast<void*>(m_audioInBuf),
313 static_cast<void*>(Buffer), samples_per_avframe * sampleSizeIn);
315 }
316 if (av_sample_fmt_is_planar(avctx->sample_fmt))
317 {
320 samples_per_avframe * sampleSizeOut);
321
322 // init AVFrame for planar data (input is interleaved)
323 for (int j = 0, jj = 0; j < m_audioChannels; j++, jj += m_audioFrameSize)
324 m_audPicture->data[j] = m_audioInPBuf + (static_cast<ptrdiff_t>(jj) * sampleSizeOut);
325 }
326 else
327 {
328 m_audPicture->data[0] = Buffer;
329 }
330
331 m_audPicture->linesize[0] = m_audioFrameSize;
332 m_audPicture->nb_samples = m_audioFrameSize;
333 m_audPicture->format = avctx->sample_fmt;
334 m_audPicture->extended_data = m_audPicture->data;
335 m_bufferedAudioFrameTimes.push_back(Timecode);
336
337 // SUGGESTION
338 // Now that avcodec_encode_audio2 is deprecated and replaced
339 // by 2 calls, this could be optimized
340 // into separate routines or separate threads.
341 bool got_packet = false;
342 int ret = avcodec_receive_packet(avctx, pkt);
343 if (ret == 0)
344 got_packet = true;
345 if (ret == AVERROR(EAGAIN))
346 ret = 0;
347 if (ret == 0)
348 ret = avcodec_send_frame(avctx, m_audPicture);
349 // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
350 // there are 2 packets to be received while only 1 frame to be
351 // sent. The code does not cater for this. Hopefully it will not happen.
352
353 if (ret < 0)
354 {
355 std::string error;
356 LOG(VB_GENERAL, LOG_ERR, LOC + QString("audio encode error: %1 (%2)")
357 .arg(av_make_error_stdstring(error, ret)).arg(got_packet));
358 av_packet_free(&pkt);
359 return ret;
360 }
361
362 if (!got_packet)
363 {
364 av_packet_free(&pkt);
365 return ret;
366 }
367
368 std::chrono::milliseconds tc = Timecode;
369
370 if (!m_bufferedAudioFrameTimes.empty())
371 tc = m_bufferedAudioFrameTimes.takeFirst();
372
373 if (m_startingTimecodeOffset == -1ms)
374 m_startingTimecodeOffset = tc - 1ms;
376
377 if (m_avVideoCodec)
378 pkt->pts = tc.count() * m_videoStream->time_base.den / m_videoStream->time_base.num / 1000;
379 else
380 pkt->pts = tc.count() * m_audioStream->time_base.den / m_audioStream->time_base.num / 1000;
381
382 pkt->dts = AV_NOPTS_VALUE;
383 pkt->flags |= AV_PKT_FLAG_KEY;
384 pkt->stream_index = m_audioStream->index;
385
386 ret = av_interleaved_write_frame(m_ctx, pkt);
387 if (ret != 0)
388 LOG(VB_RECORD, LOG_ERR, LOC + "WriteAudioFrame(): av_interleaved_write_frame couldn't write Audio");
389
390 Timecode = tc + m_startingTimecodeOffset;
391 av_packet_unref(pkt);
392 av_packet_free(&pkt);
393 return 1;
394}
395
396int MythAVFormatWriter::WriteTextFrame(int /*VBIMode*/, unsigned char* /*Buffer*/, int /*Length*/,
397 std::chrono::milliseconds /*Timecode*/, int /*PageNumber*/)
398{
399 return 1;
400}
401
403{
404 return 1;
405}
406
408{
409 return false;
410}
411
412bool MythAVFormatWriter::ReOpen(const QString& Filename)
413{
414 bool result = m_buffer->ReOpen(Filename);
415 if (result)
416 m_filename = Filename;
417 return result;
418}
419
421{
422 AVStream *stream = avformat_new_stream(m_ctx, nullptr);
423 if (!stream)
424 {
425 LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avformat_new_stream() failed");
426 return nullptr;
427 }
428
429 stream->id = 0;
430 stream->time_base.den = 90000;
431 stream->time_base.num = 1;
432 stream->r_frame_rate.num = 0;
433 stream->r_frame_rate.den = 0;
434
435 const AVCodec *codec = avcodec_find_encoder(m_ctx->oformat->video_codec);
436 if (!codec)
437 {
438 LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avcodec_find_encoder() failed");
439 return nullptr;
440 }
441
443 AVCodecContext *context = m_codecMap.GetCodecContext(stream, codec);
444 context->codec = codec;
445 context->codec_id = m_ctx->oformat->video_codec;
446 context->codec_type = AVMEDIA_TYPE_VIDEO;
447 context->bit_rate = m_videoBitrate;
448 context->width = m_width;
449 context->height = m_height;
450
451 // c->sample_aspect_ratio.num = (int)floor(m_aspect * 10000);
452 // c->sample_aspect_ratio.den = 10000;
453
454 context->time_base = GetCodecTimeBase();
455 context->gop_size = m_keyFrameDist;
456 context->pix_fmt = AV_PIX_FMT_YUV420P;
457 context->thread_count = m_encodingThreadCount;
458 context->thread_type = FF_THREAD_SLICE;
459
460 if (context->codec_id == AV_CODEC_ID_MPEG2VIDEO)
461 {
462 context->max_b_frames = 2;
463 }
464 else if (context->codec_id == AV_CODEC_ID_MPEG1VIDEO)
465 {
466 context->mb_decision = 2;
467 }
468 else if (context->codec_id == AV_CODEC_ID_H264)
469 {
470
471 // Try to provide the widest software/device support by automatically using
472 // the Baseline profile where the given bitrate and resolution permits
473
474 if ((context->height > 720) || // Approximate highest resolution supported by Baseline 3.1
475 (context->bit_rate > 1400000)) // 14,000 Kbps aka 14Mbps maximum permissable rate for Baseline 3.1
476 {
477 context->level = 40;
478 // AVCodecContext AVOptions:
479 av_opt_set(context->priv_data, "profile", "main", 0);
480 }
481 else if ((context->height > 576) || // Approximate highest resolution supported by Baseline 3.0
482 (context->bit_rate > 1000000)) // 10,000 Kbps aka 10Mbps maximum permissable rate for Baseline 3.0
483 {
484 context->level = 31;
485 // AVCodecContext AVOptions:
486 av_opt_set(context->priv_data, "profile", "baseline", 0);
487 }
488 else
489 {
490 context->level = 30; // Baseline 3.0 is the most widely supported, but it's limited to SD
491 // AVCodecContext AVOptions:
492 av_opt_set(context->priv_data, "profile", "baseline", 0);
493 }
494
495 // AVCodecContext AVOptions:
496 context->max_b_frames = 0;
497 context->slices = 8;
498 context->flags |= AV_CODEC_FLAG_LOOP_FILTER;
499 context->me_cmp |= 1;
500 // c->me_method = ME_HEX;
501 // av_opt_set_int(c, "me_method", ME_HEX, 0);
502 av_opt_set(context, "me_method", "hex", 0);
503 context->me_subpel_quality = 6;
504 context->me_range = 16;
505 context->keyint_min = 25;
506 // c->scenechange_threshold = 40;
507 av_opt_set_int(context, "sc_threshold", 40, 0);
508 context->i_quant_factor = 0.71F;
509 // c->b_frame_strategy = 1;
510 av_opt_set_int(context, "b_strategy", 1, 0);
511 context->qcompress = 0.6F;
512 context->qmin = 10;
513 context->qmax = 51;
514 context->max_qdiff = 4;
515 context->refs = 3;
516 context->trellis = 0;
517
518 // libx264 AVOptions:
519 av_opt_set(context, "partitions", "i8x8,i4x4,p8x8,b8x8", 0);
520 av_opt_set_int(context, "direct-pred", 1, 0);
521 av_opt_set_int(context, "rc-lookahead", 0, 0);
522 av_opt_set_int(context, "fast-pskip", 1, 0);
523 av_opt_set_int(context, "mixed-refs", 1, 0);
524 av_opt_set_int(context, "8x8dct", 0, 0);
525 av_opt_set_int(context, "weightb", 0, 0);
526
527 // libx264 AVOptions:
528 av_opt_set(context->priv_data, "preset", m_encodingPreset.toLatin1().constData(), 0);
529 av_opt_set(context->priv_data, "tune", m_encodingTune.toLatin1().constData(), 0);
530 }
531
532 if(m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
533 context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
534
535 return stream;
536}
537
539{
540 if (!m_width || !m_height)
541 return false;
542
543 AVCodecContext *context = m_codecMap.GetCodecContext(m_videoStream);
544 if (avcodec_open2(context, nullptr, nullptr) < 0)
545 {
546 LOG(VB_RECORD, LOG_ERR, LOC + "OpenVideo(): avcodec_open() failed");
547 return false;
548 }
549
550 if (!m_picture)
551 {
552 m_picture = AllocPicture(context->pix_fmt);
553 if (!m_picture)
554 {
555 LOG(VB_RECORD, LOG_ERR, LOC + "OpenVideo(): AllocPicture() failed");
556 return false;
557 }
558 }
559 else
560 {
561 av_frame_unref(m_picture);
562 }
563
564 return true;
565}
566
568{
569 AVStream *stream = avformat_new_stream(m_ctx, nullptr);
570 if (!stream)
571 {
572 LOG(VB_RECORD, LOG_ERR, LOC + "AddAudioStream(): avformat_new_stream() failed");
573 return nullptr;
574 }
575 stream->id = 1;
576
577 AVCodecContext *context = m_codecMap.GetCodecContext(stream, nullptr, true);
578
579 context->codec_id = m_ctx->oformat->audio_codec;
580 context->codec_type = AVMEDIA_TYPE_AUDIO;
581 context->bit_rate = m_audioBitrate;
582 context->sample_rate = m_audioFrameRate;
583 av_channel_layout_default(&(context->ch_layout), m_audioChannels);
584
585 // c->flags |= CODEC_FLAG_QSCALE; // VBR
586 // c->global_quality = blah;
587
588 if (!m_avVideoCodec)
589 {
590 context->time_base = GetCodecTimeBase();
591 stream->time_base.den = 90000;
592 stream->time_base.num = 1;
593 }
594
595 if (m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
596 context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
597
598 return stream;
599}
600
601bool MythAVFormatWriter::FindAudioFormat(AVCodecContext *Ctx, const AVCodec *Codec, AVSampleFormat Format)
602{
603 const AVSampleFormat *sample_fmts = nullptr;
604 int out_num_configs = 0;
605 int ret = avcodec_get_supported_config(nullptr, Codec, AV_CODEC_CONFIG_SAMPLE_FORMAT,
606 0, (const void **) &sample_fmts, &out_num_configs);
607 if (ret < 0)
608 return false;
609
610 if (sample_fmts)
611 {
612 for (int i = 0; i < out_num_configs; i++)
613 {
614 if (av_get_packed_sample_fmt(sample_fmts[i]) == Format)
615 {
616 Ctx->sample_fmt = sample_fmts[i];
617 return true;
618 }
619 }
620 }
621 return false;
622}
623
625{
626 AVCodecContext *context = m_codecMap.GetCodecContext(m_audioStream);
627 context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
628
629 const AVCodec *codec = avcodec_find_encoder(context->codec_id);
630 if (!codec)
631 {
632 LOG(VB_RECORD, LOG_ERR, LOC + "OpenAudio(): avcodec_find_encoder() failed");
633 return false;
634 }
635
636 // try to find suitable format we can use. avcodec_open2 will fail if we don't
637 // find one, so no need to worry otherwise. Can only handle S16 or FLOAT
638 // we give priority to S16 as libmp3lame requires aligned floats which we can't guarantee
639 if (!FindAudioFormat(context, codec, AV_SAMPLE_FMT_S16))
640 FindAudioFormat(context, codec, AV_SAMPLE_FMT_FLT);
641
642 if (avcodec_open2(context, codec, nullptr) < 0)
643 {
644 LOG(VB_RECORD, LOG_ERR, LOC + "OpenAudio(): avcodec_open() failed");
645 return false;
646 }
647
648 m_audioFrameSize = context->frame_size; // number of *samples* per channel in an AVFrame
649
650 m_audPicture = av_frame_alloc();
651 if (!m_audPicture)
652 {
653 LOG(VB_RECORD, LOG_ERR, LOC + "OpenAudio(): alloc_frame() failed");
654 return false;
655 }
656
657 auto size = static_cast<size_t>(m_audioFrameSize) * m_audioChannels *
658 av_get_bytes_per_sample(context->sample_fmt);
659 if (av_get_packed_sample_fmt(context->sample_fmt) == AV_SAMPLE_FMT_FLT)
660 {
661 // allocate buffer to convert from S16 to float
662 m_audioInBuf = static_cast<unsigned char*>(av_malloc(size));
663 if (m_audioInBuf == nullptr)
664 return false;
665 }
666
667 if (av_sample_fmt_is_planar(context->sample_fmt))
668 {
669 // allocate buffer to convert interleaved to planar audio
670 m_audioInPBuf = static_cast<unsigned char*>(av_malloc(size));
671 if (m_audioInPBuf == nullptr)
672 return false;
673 }
674 return true;
675}
676
677AVFrame* MythAVFormatWriter::AllocPicture(enum AVPixelFormat PixFmt)
678{
679 AVFrame *picture = av_frame_alloc();
680 if (!picture)
681 {
682 LOG(VB_RECORD, LOG_ERR, LOC + "AllocPicture failed");
683 return nullptr;
684 }
685
686 int size = av_image_get_buffer_size(PixFmt, m_width, m_height, IMAGE_ALIGN);
687 auto *buffer = static_cast<unsigned char*>(av_malloc(static_cast<size_t>(size)));
688 if (!buffer)
689 {
690 LOG(VB_RECORD, LOG_ERR, LOC + "AllocPicture(): av_malloc() failed");
691 av_frame_free(&picture);
692 return nullptr;
693 }
694
695 av_image_fill_arrays(picture->data, picture->linesize, buffer, PixFmt, m_width, m_height, IMAGE_ALIGN);
696 return picture;
697}
698
700{
701 AVRational result;
702 result.den = static_cast<int>(floor(m_frameRate * 100));
703 result.num = 100;
704
705 if (m_avVideoCodec)
706 {
707 const AVRational *supported_framerates = nullptr;
708 int out_num_configs = 0;
709 int ret = avcodec_get_supported_config(nullptr, m_avVideoCodec, AV_CODEC_CONFIG_FRAME_RATE,
710 0, (const void **) &supported_framerates, &out_num_configs);
711 if (ret >= 0)
712 {
713 const AVRational *best = nullptr;
714 AVRational best_error = { INT_MAX, 1 };
715 for (int i = 0; i < out_num_configs; i++)
716 {
717 AVRational error = av_sub_q(result, supported_framerates[i]);
718 if (error.num < 0)
719 error.num *= -1;
720 if (av_cmp_q(error, best_error) < 0)
721 {
722 best_error = error;
723 best = supported_framerates + i;
724 }
725 }
726
727 if (best && best->num && best->den)
728 {
729 result.den = best->num;
730 result.num = best->den;
731 }
732 }
733 }
734
735 if (result.den == 2997)
736 {
737 result.den = 30000;
738 result.num = 1001;
739 }
740 else if (result.den == 5994)
741 {
742 result.den = 60000;
743 result.num = 1001;
744 }
745
746 return result;
747}
AVFrame AVFrame
@ FORMAT_S16
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
void DeinterleaveSamples(int channels, uint8_t *output, const uint8_t *input, int data_size)
static int SampleSize(AudioFormat format)
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
AVIOContext * getAVIOContext()
unsigned char * m_audioInPBuf
bool SwitchToNextFile(void) override
AVFrame * AllocPicture(enum AVPixelFormat PixFmt)
bool OpenFile(void) override
QList< std::chrono::milliseconds > m_bufferedVideoFrameTimes
MythAVFormatBuffer * m_avfBuffer
AVStream * AddVideoStream(void)
bool Init(void) override
int WriteSeekTable(void) override
bool CloseFile(void) override
AVStream * AddAudioStream(void)
const AVCodec * m_avAudioCodec
int WriteTextFrame(int VBIMode, unsigned char *Buffer, int Length, std::chrono::milliseconds Timecode, int PageNumber) override
int WriteVideoFrame(MythVideoFrame *Frame) override
int WriteAudioFrame(unsigned char *Buffer, int FrameNumber, std::chrono::milliseconds &Timecode) override
static bool FindAudioFormat(AVCodecContext *Ctx, const AVCodec *Codec, AVSampleFormat Format)
QList< std::chrono::milliseconds > m_bufferedAudioFrameTimes
const AVCodec * m_avVideoCodec
MythMediaBuffer * m_buffer
unsigned char * m_audioInBuf
QList< int > m_bufferedVideoFrameTypes
AVRational GetCodecTimeBase(void)
AVFormatContext * m_ctx
AVOutputFormat m_fmt
bool ReOpen(const QString &Filename)
static int FillAVFrame(AVFrame *Frame, const MythVideoFrame *From, AVPixelFormat Fmt=AV_PIX_FMT_NONE)
Initialise AVFrame with content from MythVideoFrame.
Definition: mythavutil.cpp:199
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
Definition: mythavutil.cpp:288
void FreeCodecContext(const AVStream *Stream)
Definition: mythavutil.cpp:333
QString GetLastError(void) const
virtual bool ReOpen(const QString &="")
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
long long m_framesWritten
QString m_encodingTune
QString m_encodingPreset
std::chrono::milliseconds m_startingTimecodeOffset
unsigned int uint
Definition: compat.h:60
unsigned short uint16_t
Definition: iso6937tables.h:3
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
Definition: mythaverror.cpp:42
#define LOC
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def error(message)
Definition: smolt.py:409