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
29#include "libmyth/mythaverror.h"
31#include "mythavutil.h"
32
33
34// FFmpeg
35extern "C" {
36#include "libavutil/opt.h"
37#include "libavutil/samplefmt.h"
38#include "libavutil/imgutils.h"
39}
40
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)
44
46{
48
49 av_freep(reinterpret_cast<void*>(&m_audioInBuf));
50 av_freep(reinterpret_cast<void*>(&m_audioInPBuf));
51 if (m_audPicture)
52 av_frame_free(&m_audPicture);
53 Cleanup();
54 av_frame_free(&m_picture);
55}
56
58{
59 const AVOutputFormat *fmt = av_guess_format(m_container.toLatin1().constData(), nullptr, nullptr);
60 if (!fmt)
61 {
62 LOG(VB_RECORD, LOG_ERR, LOC + QString("Init(): Unable to guess AVOutputFormat from container %1")
63 .arg(m_container));
64 return false;
65 }
66
67 m_fmt = *fmt;
68
69 if (m_width && m_height)
70 {
71 m_avVideoCodec = avcodec_find_encoder_by_name(m_videoCodec.toLatin1().constData());
72 if (!m_avVideoCodec)
73 {
74 LOG(VB_RECORD, LOG_ERR, LOC + QString("Init(): Unable to find video codec %1")
75 .arg(m_videoCodec));
76 return false;
77 }
78 m_fmt.video_codec = m_avVideoCodec->id;
79 }
80 else
81 {
82 m_fmt.video_codec = AV_CODEC_ID_NONE;
83 }
84
85 m_avAudioCodec = avcodec_find_encoder_by_name(m_audioCodec.toLatin1().constData());
86 if (!m_avAudioCodec)
87 {
88 LOG(VB_RECORD, LOG_ERR, LOC + QString("Init(): Unable to find audio codec %1")
89 .arg(m_audioCodec));
90 return false;
91 }
92
93 m_fmt.audio_codec = m_avAudioCodec->id;
94
95 m_ctx = avformat_alloc_context();
96 if (!m_ctx)
97 {
98 LOG(VB_RECORD, LOG_ERR, LOC + "Init(): Unable to allocate AVFormatContext");
99 return false;
100 }
101
102 m_ctx->oformat = &m_fmt;
103
104 if (m_container == "mpegts")
105 m_ctx->packet_size = 2324;
106
107 QByteArray filename = m_filename.toLatin1();
108 auto size = static_cast<size_t>(filename.size());
109 m_ctx->url = static_cast<char*>(av_malloc(size));
110 memcpy(m_ctx->url, filename.constData(), size);
111
112 if (m_fmt.video_codec != AV_CODEC_ID_NONE)
114 if (m_fmt.audio_codec != AV_CODEC_ID_NONE)
116
117 if (m_videoStream && !OpenVideo())
118 {
119 LOG(VB_RECORD, LOG_ERR, LOC + "Init(): OpenVideo() failed");
120 return false;
121 }
122
123 if (m_audioStream && !OpenAudio())
124 {
125 LOG(VB_RECORD, LOG_ERR, LOC + "Init(): OpenAudio() failed");
126 return false;
127 }
128
129 return true;
130}
131
133{
134 bool success = openFileHelper();
135 if (!success)
136 {
137 Cleanup();
138 }
139 return success;
140}
141
143{
144 delete m_buffer;
146
147 if (!m_buffer || !m_buffer->GetLastError().isEmpty())
148 {
149 LOG(VB_RECORD, LOG_ERR, LOC + QString("OpenFile(): RingBuffer::Create() failed: '%1'")
150 .arg(m_buffer ? m_buffer->GetLastError() : ""));
151 return false;
152 }
153
154 delete m_avfBuffer;
155 m_avfBuffer = nullptr;
156 m_ctx->pb = nullptr;
157 if (!(m_fmt.flags & AVFMT_NOFILE))
158 {
159 m_avfBuffer = new MythAVFormatBuffer(m_buffer, true, true);
161 if (m_ctx->pb == nullptr)
162 {
163 LOG(VB_RECORD, LOG_ERR, LOC + "OpenFile(): failed to allocate AVIOContext");
164 return false;
165 }
166 }
167
168 if (avformat_write_header(m_ctx, nullptr) < 0)
169 {
170 return false;
171 }
172
173 return true;
174}
175
177{
178 delete m_avfBuffer;
179 m_avfBuffer = nullptr;
180 delete m_buffer;
181 m_buffer = nullptr;
182}
183
185{
186 if (m_ctx)
187 {
188 av_write_trailer(m_ctx);
189 delete m_avfBuffer;
190 m_avfBuffer = nullptr;
191 m_ctx->pb = nullptr;
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));
195 }
196 return true;
197}
198
200{
201 return (m_bufferedVideoFrameTypes.isEmpty()) ||
202 (m_bufferedVideoFrameTypes.first() == AV_PICTURE_TYPE_I);
203}
204
206{
207 long long framesEncoded = m_framesWritten + m_bufferedVideoFrameTimes.size();
208
209 av_frame_unref(m_picture);
211 m_picture->pts = framesEncoded + 1;
212 m_picture->pict_type = ((framesEncoded % m_keyFrameDist) == 0) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_NONE;
213
214 m_bufferedVideoFrameTimes.push_back(Frame->m_timecode);
215 m_bufferedVideoFrameTypes.push_back(m_picture->pict_type);
216
217 AVPacket *pkt = av_packet_alloc();
218 if (pkt == nullptr)
219 {
220 LOG(VB_RECORD, LOG_ERR, "packet allocation failed");
221 return AVERROR(ENOMEM);
222 }
223
224 AVCodecContext *avctx = m_codecMap.GetCodecContext(m_videoStream);
225
226 // SUGGESTION
227 // Now that avcodec_encode_video2 is removed and replaced
228 // by 2 calls, this could be optimized
229 // into separate routines or separate threads.
230 bool got_packet = false;
231 int ret = avcodec_receive_packet(avctx, pkt);
232 if (ret == 0)
233 got_packet = true;
234 if (ret == AVERROR(EAGAIN))
235 ret = 0;
236 if (ret == 0)
237 ret = avcodec_send_frame(avctx, m_picture);
238 // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
239 // there are 2 packets to be received while only 1 frame to be
240 // sent. The code does not cater for this. Hopefully it will not happen.
241
242 if (ret < 0)
243 {
244 std::string error;
245 LOG(VB_GENERAL, LOG_ERR, LOC + QString("video encode error: %1 (%2)")
246 .arg(av_make_error_stdstring(error, ret)).arg(got_packet));
247 av_packet_free(&pkt);
248 return ret;
249 }
250
251 if (!got_packet)
252 {
253 av_packet_free(&pkt);
254 return ret;
255 }
256
257 std::chrono::milliseconds tc = Frame->m_timecode;
258
259 if (!m_bufferedVideoFrameTimes.isEmpty())
260 tc = m_bufferedVideoFrameTimes.takeFirst();
261
262 if (!m_bufferedVideoFrameTypes.isEmpty())
263 {
264 int pict_type = m_bufferedVideoFrameTypes.takeFirst();
265 if (pict_type == AV_PICTURE_TYPE_I)
266 pkt->flags |= AV_PKT_FLAG_KEY;
267 }
268
269 if (m_startingTimecodeOffset == -1ms)
270 m_startingTimecodeOffset = tc - 1ms;
272
273 pkt->pts = tc.count() * m_videoStream->time_base.den / m_videoStream->time_base.num / 1000;
274 pkt->dts = AV_NOPTS_VALUE;
275 pkt->stream_index= m_videoStream->index;
276
277 ret = av_interleaved_write_frame(m_ctx, pkt);
278 if (ret != 0)
279 LOG(VB_RECORD, LOG_ERR, LOC + "WriteVideoFrame(): av_interleaved_write_frame couldn't write Video");
280
281 Frame->m_timecode = tc + m_startingTimecodeOffset;
283 av_packet_unref(pkt);
284 av_packet_free(&pkt);
285 return 1;
286}
287
288int MythAVFormatWriter::WriteAudioFrame(unsigned char *Buffer, int /*FrameNumber*/, std::chrono::milliseconds &Timecode)
289{
290#if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
291 auto buf16 = reinterpret_cast<uint16_t *>(Buffer);
292 for (int i = 0; i < m_audioChannels * m_audioFrameSize; i++)
293 buf16[i] = qFromLittleEndian<quint16>(buf16[i]);
294#endif
295
296 AVCodecContext *avctx = m_codecMap.GetCodecContext(m_audioStream);
297 int samples_per_avframe = m_audioFrameSize * m_audioChannels;
300 int sampleSizeOut = AudioOutputSettings::SampleSize(format);
301
302 AVPacket *pkt = av_packet_alloc();
303 if (pkt == nullptr)
304 {
305 LOG(VB_RECORD, LOG_ERR, "packet allocation failed");
306 return AVERROR(ENOMEM);
307 }
308
309 if (av_get_packed_sample_fmt(avctx->sample_fmt) == AV_SAMPLE_FMT_FLT)
310 {
312 static_cast<void*>(Buffer), samples_per_avframe * sampleSizeIn);
314 }
315 if (av_sample_fmt_is_planar(avctx->sample_fmt))
316 {
319 samples_per_avframe * sampleSizeOut);
320
321 // init AVFrame for planar data (input is interleaved)
322 for (int j = 0, jj = 0; j < m_audioChannels; j++, jj += m_audioFrameSize)
323 m_audPicture->data[j] = m_audioInPBuf + (static_cast<ptrdiff_t>(jj) * sampleSizeOut);
324 }
325 else
326 {
327 m_audPicture->data[0] = Buffer;
328 }
329
330 m_audPicture->linesize[0] = m_audioFrameSize;
331 m_audPicture->nb_samples = m_audioFrameSize;
332 m_audPicture->format = avctx->sample_fmt;
333 m_audPicture->extended_data = m_audPicture->data;
334 m_bufferedAudioFrameTimes.push_back(Timecode);
335
336 // SUGGESTION
337 // Now that avcodec_encode_audio2 is deprecated and replaced
338 // by 2 calls, this could be optimized
339 // into separate routines or separate threads.
340 bool got_packet = false;
341 int ret = avcodec_receive_packet(avctx, pkt);
342 if (ret == 0)
343 got_packet = true;
344 if (ret == AVERROR(EAGAIN))
345 ret = 0;
346 if (ret == 0)
347 ret = avcodec_send_frame(avctx, m_audPicture);
348 // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
349 // there are 2 packets to be received while only 1 frame to be
350 // sent. The code does not cater for this. Hopefully it will not happen.
351
352 if (ret < 0)
353 {
354 std::string error;
355 LOG(VB_GENERAL, LOG_ERR, LOC + QString("audio encode error: %1 (%2)")
356 .arg(av_make_error_stdstring(error, ret)).arg(got_packet));
357 av_packet_free(&pkt);
358 return ret;
359 }
360
361 if (!got_packet)
362 {
363 av_packet_free(&pkt);
364 return ret;
365 }
366
367 std::chrono::milliseconds tc = Timecode;
368
369 if (!m_bufferedAudioFrameTimes.empty())
370 tc = m_bufferedAudioFrameTimes.takeFirst();
371
372 if (m_startingTimecodeOffset == -1ms)
373 m_startingTimecodeOffset = tc - 1ms;
375
376 if (m_avVideoCodec)
377 pkt->pts = tc.count() * m_videoStream->time_base.den / m_videoStream->time_base.num / 1000;
378 else
379 pkt->pts = tc.count() * m_audioStream->time_base.den / m_audioStream->time_base.num / 1000;
380
381 pkt->dts = AV_NOPTS_VALUE;
382 pkt->flags |= AV_PKT_FLAG_KEY;
383 pkt->stream_index = m_audioStream->index;
384
385 ret = av_interleaved_write_frame(m_ctx, pkt);
386 if (ret != 0)
387 LOG(VB_RECORD, LOG_ERR, LOC + "WriteAudioFrame(): av_interleaved_write_frame couldn't write Audio");
388
389 Timecode = tc + m_startingTimecodeOffset;
390 av_packet_unref(pkt);
391 av_packet_free(&pkt);
392 return 1;
393}
394
395int MythAVFormatWriter::WriteTextFrame(int /*VBIMode*/, unsigned char* /*Buffer*/, int /*Length*/,
396 std::chrono::milliseconds /*Timecode*/, int /*PageNumber*/)
397{
398 return 1;
399}
400
402{
403 return 1;
404}
405
407{
408 return false;
409}
410
411bool MythAVFormatWriter::ReOpen(const QString& Filename)
412{
413 bool result = m_buffer->ReOpen(Filename);
414 if (result)
415 m_filename = Filename;
416 return result;
417}
418
420{
421 AVStream *stream = avformat_new_stream(m_ctx, nullptr);
422 if (!stream)
423 {
424 LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avformat_new_stream() failed");
425 return nullptr;
426 }
427
428 stream->id = 0;
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;
433
434 const AVCodec *codec = avcodec_find_encoder(m_ctx->oformat->video_codec);
435 if (!codec)
436 {
437 LOG(VB_RECORD, LOG_ERR, LOC + "AddVideoStream(): avcodec_find_encoder() failed");
438 return nullptr;
439 }
440
442 AVCodecContext *context = m_codecMap.GetCodecContext(stream, codec);
443 context->codec = codec;
444 context->codec_id = m_ctx->oformat->video_codec;
445 context->codec_type = AVMEDIA_TYPE_VIDEO;
446 context->bit_rate = m_videoBitrate;
447 context->width = m_width;
448 context->height = m_height;
449
450 // c->sample_aspect_ratio.num = (int)floor(m_aspect * 10000);
451 // c->sample_aspect_ratio.den = 10000;
452
453 context->time_base = GetCodecTimeBase();
454 context->gop_size = m_keyFrameDist;
455 context->pix_fmt = AV_PIX_FMT_YUV420P;
456 context->thread_count = m_encodingThreadCount;
457 context->thread_type = FF_THREAD_SLICE;
458
459 if (context->codec_id == AV_CODEC_ID_MPEG2VIDEO)
460 {
461 context->max_b_frames = 2;
462 }
463 else if (context->codec_id == AV_CODEC_ID_MPEG1VIDEO)
464 {
465 context->mb_decision = 2;
466 }
467 else if (context->codec_id == AV_CODEC_ID_H264)
468 {
469
470 // Try to provide the widest software/device support by automatically using
471 // the Baseline profile where the given bitrate and resolution permits
472
473 if ((context->height > 720) || // Approximate highest resolution supported by Baseline 3.1
474 (context->bit_rate > 1400000)) // 14,000 Kbps aka 14Mbps maximum permissable rate for Baseline 3.1
475 {
476 context->level = 40;
477 // AVCodecContext AVOptions:
478 av_opt_set(context->priv_data, "profile", "main", 0);
479 }
480 else if ((context->height > 576) || // Approximate highest resolution supported by Baseline 3.0
481 (context->bit_rate > 1000000)) // 10,000 Kbps aka 10Mbps maximum permissable rate for Baseline 3.0
482 {
483 context->level = 31;
484 // AVCodecContext AVOptions:
485 av_opt_set(context->priv_data, "profile", "baseline", 0);
486 }
487 else
488 {
489 context->level = 30; // Baseline 3.0 is the most widely supported, but it's limited to SD
490 // AVCodecContext AVOptions:
491 av_opt_set(context->priv_data, "profile", "baseline", 0);
492 }
493
494 // AVCodecContext AVOptions:
495 context->max_b_frames = 0;
496 context->slices = 8;
497 context->flags |= AV_CODEC_FLAG_LOOP_FILTER;
498 context->me_cmp |= 1;
499 // c->me_method = ME_HEX;
500 // av_opt_set_int(c, "me_method", ME_HEX, 0);
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;
505 // c->scenechange_threshold = 40;
506 av_opt_set_int(context, "sc_threshold", 40, 0);
507 context->i_quant_factor = 0.71F;
508 // c->b_frame_strategy = 1;
509 av_opt_set_int(context, "b_strategy", 1, 0);
510 context->qcompress = 0.6F;
511 context->qmin = 10;
512 context->qmax = 51;
513 context->max_qdiff = 4;
514 context->refs = 3;
515 context->trellis = 0;
516
517 // libx264 AVOptions:
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);
525
526 // libx264 AVOptions:
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);
529 }
530
531 if(m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
532 context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
533
534 return stream;
535}
536
538{
539 if (!m_width || !m_height)
540 return false;
541
542 AVCodecContext *context = m_codecMap.GetCodecContext(m_videoStream);
543 if (avcodec_open2(context, nullptr, nullptr) < 0)
544 {
545 LOG(VB_RECORD, LOG_ERR, LOC + "OpenVideo(): avcodec_open() failed");
546 return false;
547 }
548
549 if (!m_picture)
550 {
551 m_picture = AllocPicture(context->pix_fmt);
552 if (!m_picture)
553 {
554 LOG(VB_RECORD, LOG_ERR, LOC + "OpenVideo(): AllocPicture() failed");
555 return false;
556 }
557 }
558 else
559 {
560 av_frame_unref(m_picture);
561 }
562
563 return true;
564}
565
567{
568 AVStream *stream = avformat_new_stream(m_ctx, nullptr);
569 if (!stream)
570 {
571 LOG(VB_RECORD, LOG_ERR, LOC + "AddAudioStream(): avformat_new_stream() failed");
572 return nullptr;
573 }
574 stream->id = 1;
575
576 AVCodecContext *context = m_codecMap.GetCodecContext(stream, nullptr, true);
577
578 context->codec_id = m_ctx->oformat->audio_codec;
579 context->codec_type = AVMEDIA_TYPE_AUDIO;
580 context->bit_rate = m_audioBitrate;
581 context->sample_rate = m_audioFrameRate;
582 av_channel_layout_default(&(context->ch_layout), m_audioChannels);
583
584 // c->flags |= CODEC_FLAG_QSCALE; // VBR
585 // c->global_quality = blah;
586
587 if (!m_avVideoCodec)
588 {
589 context->time_base = GetCodecTimeBase();
590 stream->time_base.den = 90000;
591 stream->time_base.num = 1;
592 }
593
594 if (m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
595 context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
596
597 return stream;
598}
599
600bool MythAVFormatWriter::FindAudioFormat(AVCodecContext *Ctx, const AVCodec *Codec, AVSampleFormat Format)
601{
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);
606 if (ret < 0)
607 return false;
608
609 if (sample_fmts)
610 {
611 for (int i = 0; i < out_num_configs; i++)
612 {
613 if (av_get_packed_sample_fmt(sample_fmts[i]) == Format)
614 {
615 Ctx->sample_fmt = sample_fmts[i];
616 return true;
617 }
618 }
619 }
620 return false;
621}
622
624{
625 AVCodecContext *context = m_codecMap.GetCodecContext(m_audioStream);
626 context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
627
628 const AVCodec *codec = avcodec_find_encoder(context->codec_id);
629 if (!codec)
630 {
631 LOG(VB_RECORD, LOG_ERR, LOC + "OpenAudio(): avcodec_find_encoder() failed");
632 return false;
633 }
634
635 // try to find suitable format we can use. avcodec_open2 will fail if we don't
636 // find one, so no need to worry otherwise. Can only handle S16 or FLOAT
637 // we give priority to S16 as libmp3lame requires aligned floats which we can't guarantee
638 if (!FindAudioFormat(context, codec, AV_SAMPLE_FMT_S16))
639 FindAudioFormat(context, codec, AV_SAMPLE_FMT_FLT);
640
641 if (avcodec_open2(context, codec, nullptr) < 0)
642 {
643 LOG(VB_RECORD, LOG_ERR, LOC + "OpenAudio(): avcodec_open() failed");
644 return false;
645 }
646
647 m_audioFrameSize = context->frame_size; // number of *samples* per channel in an AVFrame
648
649 m_audPicture = av_frame_alloc();
650 if (!m_audPicture)
651 {
652 LOG(VB_RECORD, LOG_ERR, LOC + "OpenAudio(): alloc_frame() failed");
653 return false;
654 }
655
656 auto size = static_cast<size_t>(m_audioFrameSize) * m_audioChannels *
657 av_get_bytes_per_sample(context->sample_fmt);
658 if (av_get_packed_sample_fmt(context->sample_fmt) == AV_SAMPLE_FMT_FLT)
659 {
660 // allocate buffer to convert from S16 to float
661 m_audioInBuf = static_cast<unsigned char*>(av_malloc(size));
662 if (m_audioInBuf == nullptr)
663 return false;
664 }
665
666 if (av_sample_fmt_is_planar(context->sample_fmt))
667 {
668 // allocate buffer to convert interleaved to planar audio
669 m_audioInPBuf = static_cast<unsigned char*>(av_malloc(size));
670 if (m_audioInPBuf == nullptr)
671 return false;
672 }
673 return true;
674}
675
676AVFrame* MythAVFormatWriter::AllocPicture(enum AVPixelFormat PixFmt)
677{
678 AVFrame *picture = av_frame_alloc();
679 if (!picture)
680 {
681 LOG(VB_RECORD, LOG_ERR, LOC + "AllocPicture failed");
682 return nullptr;
683 }
684
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)));
687 if (!buffer)
688 {
689 LOG(VB_RECORD, LOG_ERR, LOC + "AllocPicture(): av_malloc() failed");
690 av_frame_free(&picture);
691 return nullptr;
692 }
693
694 av_image_fill_arrays(picture->data, picture->linesize, buffer, PixFmt, m_width, m_height, IMAGE_ALIGN);
695 return picture;
696}
697
699{
700 AVRational result;
701 result.den = static_cast<int>(floor(m_frameRate * 100));
702 result.num = 100;
703
704 if (m_avVideoCodec)
705 {
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);
710 if (ret >= 0)
711 {
712 const AVRational *best = nullptr;
713 AVRational best_error = { INT_MAX, 1 };
714 for (int i = 0; i < out_num_configs; i++)
715 {
716 AVRational error = av_sub_q(result, supported_framerates[i]);
717 if (error.num < 0)
718 error.num *= -1;
719 if (av_cmp_q(error, best_error) < 0)
720 {
721 best_error = error;
722 best = supported_framerates + i;
723 }
724 }
725
726 if (best && best->num && best->den)
727 {
728 result.den = best->num;
729 result.num = best->den;
730 }
731 }
732 }
733
734 if (result.den == 2997)
735 {
736 result.den = 30000;
737 result.num = 1001;
738 }
739 else if (result.den == 5994)
740 {
741 result.den = 60000;
742 result.num = 1001;
743 }
744
745 return result;
746}
AVFrame AVFrame
@ FORMAT_S16
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.
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: freesurround.h:24
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