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