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