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