MythTV  master
transcode.cpp
Go to the documentation of this file.
1 // C++
2 #include <cmath>
3 #include <fcntl.h>
4 #include <iostream>
5 #include <memory>
6 #include <unistd.h> // for unlink()
7 
8 // Qt
9 #include <QList>
10 #include <QMap>
11 #include <QMutex>
12 #include <QMutexLocker>
13 #include <QRegularExpression>
14 #include <QStringList>
15 #include <QWaitCondition>
16 #include <QtAlgorithms>
17 
18 // MythTV
19 #include "libmythbase/mythconfig.h"
20 
22 #include "libmythbase/exitcodes.h"
25 #include "libmythbase/mythdbcon.h"
28 #include "libmythtv/deletemap.h"
30 #include "libmythtv/jobqueue.h"
31 #include "libmythtv/mythavutil.h"
33 #include "libmythtv/tvremoteutil.h"
34 #if CONFIG_LIBMP3LAME
36 #endif
37 
38 // MythTranscode
39 #include "audioreencodebuffer.h"
40 #include "cutter.h"
41 #include "mythtranscodeplayer.h"
42 #include "transcode.h"
43 #include "videodecodebuffer.h"
44 
45 extern "C" {
46 #include "libavcodec/avcodec.h"
47 #include "libswscale/swscale.h"
48 }
49 
50 #define LOC QString("Transcode: ")
51 
53  m_proginfo(pginfo),
54  m_recProfile(new RecordingProfile("Transcoders"))
55 {
56 }
57 
59 {
60 #if CONFIG_LIBMP3LAME
61  delete m_nvr;
62 #endif
63  SetPlayerContext(nullptr);
64  delete m_outBuffer;
65  delete m_fifow;
66  delete m_kfaTable;
67  delete m_recProfile;
68 }
69 void Transcode::ReencoderAddKFA(long curframe, long lastkey, long num_keyframes)
70 {
71  long delta = curframe - lastkey;
72  if (delta != 0 && delta != m_keyframeDist)
73  {
74  struct kfatable_entry kfate {};
75  kfate.adjust = m_keyframeDist - delta;
76  kfate.keyframe_number = num_keyframes;
77  m_kfaTable->push_back(kfate);
78  }
79 }
80 
81 bool Transcode::GetProfile(const QString& profileName, const QString& encodingType,
82  int height, int frameRate)
83 {
84  if (profileName.toLower() == "autodetect")
85  {
86  if (height == 1088)
87  height = 1080;
88 
89  QString autoProfileName = QObject::tr("Autodetect from %1").arg(height);
90  if (frameRate == 25 || frameRate == 30)
91  autoProfileName += "i";
92  if (frameRate == 50 || frameRate == 60)
93  autoProfileName += "p";
94 
95  bool result = false;
96  LOG(VB_GENERAL, LOG_NOTICE,
97  QString("Transcode: Looking for autodetect profile: %1")
98  .arg(autoProfileName));
99  result = m_recProfile->loadByGroup(autoProfileName, "Transcoders");
100 
101  if (!result && encodingType == "MPEG-2")
102  {
103  result = m_recProfile->loadByGroup("MPEG2", "Transcoders");
104  autoProfileName = "MPEG2";
105  }
106  if (!result && (encodingType == "MPEG-4" || encodingType == "RTjpeg"))
107  {
108  result = m_recProfile->loadByGroup("RTjpeg/MPEG4",
109  "Transcoders");
110  autoProfileName = "RTjpeg/MPEG4";
111  }
112  if (!result)
113  {
114  LOG(VB_GENERAL, LOG_ERR,
115  QString("Transcode: Couldn't find profile for : %1")
116  .arg(encodingType));
117 
118  return false;
119  }
120 
121  LOG(VB_GENERAL, LOG_NOTICE,
122  QString("Transcode: Using autodetect profile: %1")
123  .arg(autoProfileName));
124  }
125  else
126  {
127  bool isNum = false;
128  int profileID = profileName.toInt(&isNum);
129  // If a bad profile is specified, there will be trouble
130  if (isNum && profileID > 0)
131  m_recProfile->loadByID(profileID);
132  else if (!m_recProfile->loadByGroup(profileName, "Transcoders"))
133  {
134  LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find profile #: %1")
135  .arg(profileName));
136  return false;
137  }
138  }
139  return true;
140 }
141 
143 {
144  if (player_ctx == m_ctx)
145  return;
146 
147  delete m_ctx;
148  m_ctx = player_ctx;
149 }
150 
151 #if CONFIG_LIBMP3LAME
152 static QString get_str_option(RecordingProfile *profile, const QString &name)
153 {
154  const StandardSetting *setting = profile->byName(name);
155  if (setting)
156  return setting->getValue();
157 
158  LOG(VB_GENERAL, LOG_ERR, LOC +
159  QString("get_str_option(...%1): Option not in profile.").arg(name));
160 
161  return {};
162 }
163 
164 static int get_int_option(RecordingProfile *profile, const QString &name)
165 {
166  QString ret_str = get_str_option(profile, name);
167  if (ret_str.isEmpty())
168  return 0;
169 
170  bool ok = false;
171  int ret_int = ret_str.toInt(&ok);
172 
173  if (!ok)
174  {
175  LOG(VB_GENERAL, LOG_ERR, LOC +
176  QString("get_int_option(...%1): Option is not an int.").arg(name));
177  }
178 
179  return ret_int;
180 }
181 
182 static bool get_bool_option(RecordingProfile *profile, const QString &name)
183 {
184  return get_int_option(profile, name) != 0;
185 }
186 
187 static void TranscodeWriteText(void *ptr, unsigned char *buf, int len,
188  std::chrono::milliseconds timecode, int pagenr)
189 {
190  auto *nvr = (NuppelVideoRecorder *)ptr;
191  nvr->WriteText(buf, len, timecode, pagenr);
192 }
193 #endif // CONFIG_LIBMP3LAME
194 
195 int Transcode::TranscodeFile(const QString &inputname,
196  const QString &outputname,
197  [[maybe_unused]] const QString &profileName,
198  bool honorCutList, bool framecontrol,
199  int jobID, const QString& fifodir,
200  bool fifo_info, bool cleanCut,
201  frm_dir_map_t &deleteMap,
202  int AudioTrackNo,
203  bool passthru)
204 {
205  QDateTime curtime = MythDate::current();
206  QDateTime statustime = curtime;
207  int audioFrame = 0;
208  std::unique_ptr<Cutter> cutter = nullptr;
209  std::unique_ptr<MythAVFormatWriter> avfw = nullptr;
210  std::unique_ptr<MythAVFormatWriter> avfw2 = nullptr;
211  std::unique_ptr<HTTPLiveStream> hls = nullptr;
212  int hlsSegmentSize = 0;
213  int hlsSegmentFrames = 0;
214 
215  if (jobID >= 0)
216  JobQueue::ChangeJobComment(jobID, "0% " + QObject::tr("Completed"));
217 
218  if (m_hlsMode)
219  {
220  m_avfMode = true;
221 
222  if (m_hlsStreamID != -1)
223  {
224  hls = std::make_unique<HTTPLiveStream>(m_hlsStreamID);
226  hls->UpdateStatusMessage("Transcoding Starting");
227  m_cmdWidth = hls->GetWidth();
228  m_cmdHeight = hls->GetHeight();
229  m_cmdBitrate = hls->GetBitrate();
231  }
232  }
233 
234  if (!m_avfMode)
235  {
236 #if CONFIG_LIBMP3LAME
237  m_nvr = new NuppelVideoRecorder(nullptr, nullptr);
238 #else
239  LOG(VB_GENERAL, LOG_ERR,
240  "Not compiled with libmp3lame support");
241  return REENCODE_ERROR;
242 #endif
243  }
244 
245  // Input setup
246  auto *player_ctx = new PlayerContext(kTranscoderInUseID);
247  player_ctx->SetPlayingInfo(m_proginfo);
248  MythMediaBuffer *rb = (hls && (m_hlsStreamID != -1)) ?
249  MythMediaBuffer::Create(hls->GetSourceFile(), false, false) :
250  MythMediaBuffer::Create(inputname, false, false);
251  if (!rb || !rb->GetLastError().isEmpty())
252  {
253  LOG(VB_GENERAL, LOG_ERR,
254  QString("Transcoding aborted, error: '%1'")
255  .arg(rb? rb->GetLastError() : ""));
256  delete player_ctx;
257  return REENCODE_ERROR;
258  }
259  player_ctx->SetRingBuffer(rb);
260  player_ctx->SetPlayer(new MythTranscodePlayer(player_ctx, static_cast<PlayerFlags>(kVideoIsNull | kNoITV)));
261  SetPlayerContext(player_ctx);
262  auto * player = dynamic_cast<MythTranscodePlayer*>(GetPlayer());
263  if (player == nullptr)
264  {
265  LOG(VB_GENERAL, LOG_ERR,
266  QString("Transcoding aborted, failed to retrieve MythPlayer object"));
267  return REENCODE_ERROR;
268  }
269  if (m_proginfo->GetRecordingEndTime() > curtime)
270  {
271  player_ctx->SetRecorder(RemoteGetExistingRecorder(m_proginfo));
272  player->SetWatchingRecording(true);
273  }
274 
275  if (m_showProgress)
276  {
277  statustime = statustime.addSecs(5);
278  }
279 
280  AudioOutput *audioOutput = new AudioReencodeBuffer(FORMAT_NONE, 0,
281  passthru);
282  AudioReencodeBuffer *arb = ((AudioReencodeBuffer*)audioOutput);
283  player->GetAudio()->SetAudioOutput(audioOutput);
284  player->SetTranscoding(true);
285 
286  if (player->OpenFile() < 0)
287  {
288  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, error opening file.");
289  SetPlayerContext(nullptr);
290  return REENCODE_ERROR;
291  }
292 
293  if (AudioTrackNo > -1)
294  {
295  LOG(VB_GENERAL, LOG_INFO,
296  QString("Set audiotrack number to %1").arg(AudioTrackNo));
297  player->GetDecoder()->SetTrack(kTrackTypeAudio, AudioTrackNo);
298  }
299 
300  long long total_frame_count = player->GetTotalFrameCount();
301  long long new_frame_count = total_frame_count;
302  if (honorCutList && m_proginfo)
303  {
304  LOG(VB_GENERAL, LOG_INFO, "Honoring the cutlist while transcoding");
305 
306  frm_dir_map_t::const_iterator it;
307  QString cutStr;
308  long long lastStart = 0;
309 
310  if (deleteMap.empty())
311  m_proginfo->QueryCutList(deleteMap);
312 
313  for (it = deleteMap.cbegin(); it != deleteMap.cend(); ++it)
314  {
315  if (*it)
316  {
317  if (!cutStr.isEmpty())
318  cutStr += ",";
319  cutStr += QString("%1-").arg((long)it.key());
320  lastStart = it.key();
321  }
322  else
323  {
324  if (cutStr.isEmpty())
325  cutStr += "0-";
326  cutStr += QString("%1").arg((long)it.key());
327  new_frame_count -= (it.key() - lastStart);
328  }
329  }
330  if (cutStr.isEmpty())
331  cutStr = "Is Empty";
332  else if (cutStr.endsWith('-') && (total_frame_count > lastStart))
333  {
334  new_frame_count -= (total_frame_count - lastStart);
335  cutStr += QString("%1").arg(total_frame_count);
336  }
337  LOG(VB_GENERAL, LOG_INFO, QString("Cutlist : %1").arg(cutStr));
338  LOG(VB_GENERAL, LOG_INFO, QString("Original Length: %1 frames")
339  .arg((long)total_frame_count));
340  LOG(VB_GENERAL, LOG_INFO, QString("New Length : %1 frames")
341  .arg((long)new_frame_count));
342 
343  if ((m_proginfo->QueryIsEditing()) ||
345  {
346  LOG(VB_GENERAL, LOG_INFO, "Transcoding aborted, cutlist changed");
347  SetPlayerContext(nullptr);
349  }
351  curtime = curtime.addSecs(60);
352  }
353 
354  player->GetAudio()->ReinitAudio();
355  QString encodingType = player->GetEncodingType();
356  bool copyvideo = false;
357  bool copyaudio = false;
358 
359  QString vidsetting = nullptr;
360  QString audsetting = nullptr;
361  QString vidfilters = nullptr;
362 
363  QSize buf_size = player->GetVideoBufferSize();
364  int video_width = buf_size.width();
365  int video_height = buf_size.height();
366 
367  if (video_height == 1088) {
368  LOG(VB_GENERAL, LOG_NOTICE,
369  "Found video height of 1088. This is unusual and "
370  "more than likely the video is actually 1080 so mythtranscode "
371  "will treat it as such.");
372  }
373 
374  DecoderBase* dec = player->GetDecoder();
375  float video_aspect = dec ? dec->GetVideoAspect() : 4.0F / 3.0F;
376  float video_frame_rate = player->GetFrameRate();
377  int newWidth = video_width;
378  int newHeight = video_height;
379  bool halfFramerate = false;
380  bool skippedLastFrame = false;
381 
382  m_kfaTable = new std::vector<struct kfatable_entry>;
383 
384  if (m_avfMode)
385  {
386  newWidth = m_cmdWidth;
387  newHeight = m_cmdHeight;
388 
389  // Absolutely no purpose is served by scaling video up beyond it's
390  // original resolution, quality is degraded, transcoding is
391  // slower and in future we may wish to scale bitrate according to
392  // resolution, so it would also waste bandwidth (when streaming)
393  //
394  // This change could be said to apply for all transcoding, but for now
395  // we're limiting it to HLS where it's uncontroversial
396  if (m_hlsMode)
397  {
398 // if (newWidth > video_width)
399 // newWidth = video_width;
400  if (newHeight > video_height)
401  {
402  newHeight = video_height;
403  newWidth = 0;
404  }
405  }
406 
407  // TODO: is this necessary? It got commented out, but may still be
408  // needed.
409  // int actualHeight = (video_height == 1088 ? 1080 : video_height);
410 
411  // If height or width are 0, then we need to calculate them
412  if (newHeight == 0 && newWidth > 0)
413  newHeight = (int)(1.0F * newWidth / video_aspect);
414  else if (newWidth == 0 && newHeight > 0)
415  newWidth = (int)(1.0F * newHeight * video_aspect);
416  else if (newWidth == 0 && newHeight == 0)
417  {
418  newHeight = 480;
419  newWidth = (int)(1.0F * 480 * video_aspect);
420  if (newWidth > 640)
421  {
422  newWidth = 640;
423  newHeight = (int)(1.0F * 640 / video_aspect);
424  }
425  }
426 
427  // make sure dimensions are valid for MPEG codecs
428  newHeight = (newHeight + 15) & ~0xF;
429  newWidth = (newWidth + 15) & ~0xF;
430 
431  avfw = std::make_unique<MythAVFormatWriter>();
432  if (!avfw)
433  {
434  LOG(VB_GENERAL, LOG_ERR,
435  "Transcoding aborted, error creating AVFormatWriter.");
436  SetPlayerContext(nullptr);
437  return REENCODE_ERROR;
438  }
439 
441  avfw->SetHeight(newHeight);
442  avfw->SetWidth(newWidth);
443  avfw->SetAspect(video_aspect);
445  avfw->SetAudioChannels(arb->m_channels);
447  avfw->SetAudioFormat(FORMAT_S16);
448 
449  if (m_hlsMode)
450  {
451 
452  if (m_hlsStreamID == -1)
453  {
454  hls = std::make_unique<HTTPLiveStream>(inputname, newWidth, newHeight,
456  m_hlsMaxSegments, 0, 0);
457 
458  m_hlsStreamID = hls->GetStreamID();
459  if (!hls || m_hlsStreamID == -1)
460  {
461  LOG(VB_GENERAL, LOG_ERR, "Unable to create new stream");
462  SetPlayerContext(nullptr);
463  return REENCODE_ERROR;
464  }
465  }
466 
467  int segmentSize = hls->GetSegmentSize();
468 
469  LOG(VB_GENERAL, LOG_NOTICE,
470  QString("HLS: Using segment size of %1 seconds")
471  .arg(segmentSize));
472 
474  {
475  int audioOnlyBitrate = hls->GetAudioOnlyBitrate();
476 
477  avfw2 = std::make_unique<MythAVFormatWriter>();
478  avfw2->SetContainer("mpegts");
479  avfw2->SetAudioCodec("aac");
480  avfw2->SetAudioBitrate(audioOnlyBitrate);
481  avfw2->SetAudioChannels(arb->m_channels);
482  avfw2->SetAudioFrameRate(arb->m_eff_audiorate);
483  avfw2->SetAudioFormat(FORMAT_S16);
484  }
485 
486  avfw->SetContainer("mpegts");
487  avfw->SetVideoCodec("libx264");
488  avfw->SetAudioCodec("aac");
490  hls->UpdateStatusMessage("Transcoding Starting");
491  hls->UpdateSizeInfo(newWidth, newHeight, video_width, video_height);
492 
493  if (!hls->InitForWrite())
494  {
495  LOG(VB_GENERAL, LOG_ERR, "hls->InitForWrite() failed");
496  SetPlayerContext(nullptr);
497  return REENCODE_ERROR;
498  }
499 
500  if (video_frame_rate > 30)
501  {
502  halfFramerate = true;
503  avfw->SetFramerate(video_frame_rate/2);
504 
505  if (avfw2)
506  avfw2->SetFramerate(video_frame_rate/2);
507 
508  hlsSegmentSize = (int)(segmentSize * video_frame_rate / 2);
509  }
510  else
511  {
512  avfw->SetFramerate(video_frame_rate);
513 
514  if (avfw2)
515  avfw2->SetFramerate(video_frame_rate);
516 
517  hlsSegmentSize = (int)(segmentSize * video_frame_rate);
518  }
519 
520  avfw->SetKeyFrameDist(30);
521  if (avfw2)
522  avfw2->SetKeyFrameDist(30);
523 
524  hls->AddSegment();
525  avfw->SetFilename(hls->GetCurrentFilename());
526  if (avfw2)
527  avfw2->SetFilename(hls->GetCurrentFilename(true));
528  }
529  else
530  {
534  avfw->SetFilename(outputname);
535  avfw->SetFramerate(video_frame_rate);
536  avfw->SetKeyFrameDist(30);
537  }
538 
539  int threads = gCoreContext->GetNumSetting("HTTPLiveStreamThreads", 2);
540  QString preset = gCoreContext->GetSetting("HTTPLiveStreamPreset", "veryfast");
541  QString tune = gCoreContext->GetSetting("HTTPLiveStreamTune", "film");
542 
543  LOG(VB_GENERAL, LOG_NOTICE,
544  QString("x264 HLS using: %1 threads, '%2' profile and '%3' tune")
545  .arg(QString::number(threads), preset, tune));
546 
547  avfw->SetThreadCount(threads);
548  avfw->SetEncodingPreset(preset);
549  avfw->SetEncodingTune(tune);
550 
551  if (avfw2)
552  avfw2->SetThreadCount(1);
553 
554  if (!avfw->Init())
555  {
556  LOG(VB_GENERAL, LOG_ERR, "avfw->Init() failed");
557  SetPlayerContext(nullptr);
558  return REENCODE_ERROR;
559  }
560 
561  if (!avfw->OpenFile())
562  {
563  LOG(VB_GENERAL, LOG_ERR, "avfw->OpenFile() failed");
564  SetPlayerContext(nullptr);
565  return REENCODE_ERROR;
566  }
567 
568  if (avfw2 && !avfw2->Init())
569  {
570  LOG(VB_GENERAL, LOG_ERR, "avfw2->Init() failed");
571  SetPlayerContext(nullptr);
572  return REENCODE_ERROR;
573  }
574 
575  if (avfw2 && !avfw2->OpenFile())
576  {
577  LOG(VB_GENERAL, LOG_ERR, "avfw2->OpenFile() failed");
578  SetPlayerContext(nullptr);
579  return REENCODE_ERROR;
580  }
581 
582  arb->m_audioFrameSize = avfw->GetAudioFrameSize() * arb->m_channels * 2;
583  }
584 #if CONFIG_LIBMP3LAME
585  else if (fifodir.isEmpty())
586  {
587  if (!GetProfile(profileName, encodingType, video_height,
588  (int)round(video_frame_rate))) {
589  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, no profile found.");
590  SetPlayerContext(nullptr);
591  return REENCODE_ERROR;
592  }
593 
594  // For overriding settings on the command line
595  QMap<QString, QString> recorderOptionsMap;
596  if (!m_recorderOptions.isEmpty())
597  {
598  QStringList options = m_recorderOptions
599  .split(",", Qt::SkipEmptyParts);
600  int loop = 0;
601  while (loop < options.size())
602  {
603  QStringList tokens = options[loop].split("=");
604  if (tokens.length() < 2)
605  {
606  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, invalid option settings.");
607  return REENCODE_ERROR;
608  }
609  recorderOptionsMap[tokens[0]] = tokens[1];
610 
611  loop++;
612  }
613  }
614 
615  vidsetting = get_str_option(m_recProfile, "videocodec");
616  audsetting = get_str_option(m_recProfile, "audiocodec");
617  vidfilters = get_str_option(m_recProfile, "transcodefilters");
618 
619  if (encodingType == "MPEG-2" &&
620  get_bool_option(m_recProfile, "transcodelossless"))
621  {
622  LOG(VB_GENERAL, LOG_NOTICE, "Switching to MPEG-2 transcoder.");
623  SetPlayerContext(nullptr);
624  return REENCODE_MPEG2TRANS;
625  }
626 
627  // Recorder setup
628  if (get_bool_option(m_recProfile, "transcodelossless"))
629  {
630  vidsetting = encodingType;
631  audsetting = "MP3";
632  }
633  else if (get_bool_option(m_recProfile, "transcoderesize"))
634  {
635  int actualHeight = (video_height == 1088 ? 1080 : video_height);
636 
637  //player->SetVideoFilters(vidfilters);
638  newWidth = get_int_option(m_recProfile, "width");
639  newHeight = get_int_option(m_recProfile, "height");
640 
641  // If height or width are 0, then we need to calculate them
642  if (newHeight == 0 && newWidth > 0)
643  newHeight = (int)(1.0 * newWidth * actualHeight / video_width);
644  else if (newWidth == 0 && newHeight > 0)
645  newWidth = (int)(1.0 * newHeight * video_width / actualHeight);
646  else if (newWidth == 0 && newHeight == 0)
647  {
648  newHeight = 480;
649  newWidth = (int)(1.0 * 480 * video_width / actualHeight);
650  if (newWidth > 640)
651  {
652  newWidth = 640;
653  newHeight = (int)(1.0 * 640 * actualHeight / video_width);
654  }
655  }
656 
657  if (encodingType.startsWith("mpeg", Qt::CaseInsensitive))
658  {
659  // make sure dimensions are valid for MPEG codecs
660  newHeight = (newHeight + 15) & ~0xF;
661  newWidth = (newWidth + 15) & ~0xF;
662  }
663 
664  LOG(VB_GENERAL, LOG_INFO, QString("Resizing from %1x%2 to %3x%4")
665  .arg(video_width).arg(video_height)
666  .arg(newWidth).arg(newHeight));
667  }
668  else // lossy and no resize
669  {
670  //player->SetVideoFilters(vidfilters);
671  }
672 
673  // this is ripped from tv_rec SetupRecording. It'd be nice to merge
674  m_nvr->SetOption("inpixfmt", FMT_YV12);
675 
676  m_nvr->SetOption("width", newWidth);
677  m_nvr->SetOption("height", newHeight);
678 
679  m_nvr->SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
680  m_nvr->SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
681 
682  m_nvr->SetFrameRate(video_frame_rate);
683  m_nvr->SetVideoAspect(video_aspect);
684  m_nvr->SetTranscoding(true);
685 
686  if ((vidsetting == "MPEG-4") ||
687  (recorderOptionsMap["videocodec"] == "mpeg4"))
688  {
689  m_nvr->SetOption("videocodec", "mpeg4");
690 
691  m_nvr->SetIntOption(m_recProfile, "mpeg4bitrate");
692  m_nvr->SetIntOption(m_recProfile, "scalebitrate");
693  m_nvr->SetIntOption(m_recProfile, "mpeg4maxquality");
694  m_nvr->SetIntOption(m_recProfile, "mpeg4minquality");
695  m_nvr->SetIntOption(m_recProfile, "mpeg4qualdiff");
696  m_nvr->SetIntOption(m_recProfile, "mpeg4optionvhq");
697  m_nvr->SetIntOption(m_recProfile, "mpeg4option4mv");
698 #ifdef USING_FFMPEG_THREADS
699  m_nvr->SetIntOption(m_recProfile, "encodingthreadcount");
700 #endif
701  }
702  else if ((vidsetting == "MPEG-2") ||
703  (recorderOptionsMap["videocodec"] == "mpeg2video"))
704  {
705  m_nvr->SetOption("videocodec", "mpeg2video");
706 
707  m_nvr->SetIntOption(m_recProfile, "mpeg2bitrate");
708  m_nvr->SetIntOption(m_recProfile, "scalebitrate");
709 #ifdef USING_FFMPEG_THREADS
710  m_nvr->SetIntOption(m_recProfile, "encodingthreadcount");
711 #endif
712  }
713  else if ((vidsetting == "RTjpeg") ||
714  (recorderOptionsMap["videocodec"] == "rtjpeg"))
715  {
716  m_nvr->SetOption("videocodec", "rtjpeg");
717  m_nvr->SetIntOption(m_recProfile, "rtjpegquality");
718  m_nvr->SetIntOption(m_recProfile, "rtjpegchromafilter");
719  m_nvr->SetIntOption(m_recProfile, "rtjpeglumafilter");
720  }
721  else if (vidsetting.isEmpty())
722  {
723  LOG(VB_GENERAL, LOG_ERR, "No video information found!");
724  LOG(VB_GENERAL, LOG_ERR, "Please ensure that recording profiles "
725  "for the transcoder are set");
726  SetPlayerContext(nullptr);
727  return REENCODE_ERROR;
728  }
729  else
730  {
731  LOG(VB_GENERAL, LOG_ERR,
732  QString("Unknown video codec: %1").arg(vidsetting));
733  SetPlayerContext(nullptr);
734  return REENCODE_ERROR;
735  }
736 
737  m_nvr->SetOption("samplerate", arb->m_eff_audiorate);
738  if (audsetting == "MP3")
739  {
740  m_nvr->SetOption("audiocompression", 1);
741  m_nvr->SetIntOption(m_recProfile, "mp3quality");
742  copyaudio = true;
743  }
744  else if (audsetting == "Uncompressed")
745  {
746  m_nvr->SetOption("audiocompression", 0);
747  }
748  else
749  {
750  LOG(VB_GENERAL, LOG_ERR,
751  QString("Unknown audio codec: %1").arg(audsetting));
752  }
753 
754  m_nvr->AudioInit(true);
755 
756  // For overriding settings on the command line
757  if (!recorderOptionsMap.empty())
758  {
759  QMap<QString, QString>::Iterator it;
760  QString key;
761  QString value;
762  for (it = recorderOptionsMap.begin();
763  it != recorderOptionsMap.end(); ++it)
764  {
765  key = it.key();
766  value = *it;
767 
768  LOG(VB_GENERAL, LOG_NOTICE,
769  QString("Forcing Recorder option '%1' to '%2'")
770  .arg(key, value));
771 
772  static const QRegularExpression kNonDigitRE { "\\D" };
773  if (value.contains(kNonDigitRE))
774  m_nvr->SetOption(key, value);
775  else
776  m_nvr->SetOption(key, value.toInt());
777 
778  if (key == "width")
779  newWidth = (value.toInt() + 15) & ~0xF;
780  else if (key == "height")
781  newHeight = (value.toInt() + 15) & ~0xF;
782  else if (key == "videocodec")
783  {
784  if (value == "mpeg4")
785  vidsetting = "MPEG-4";
786  else if (value == "mpeg2video")
787  vidsetting = "MPEG-2";
788  else if (value == "rtjpeg")
789  vidsetting = "RTjpeg";
790  }
791  }
792  }
793 
794  if ((vidsetting == "MPEG-4") ||
795  (vidsetting == "MPEG-2"))
796  m_nvr->SetupAVCodecVideo();
797  else if (vidsetting == "RTjpeg")
798  m_nvr->SetupRTjpeg();
799 
800  m_outBuffer = MythMediaBuffer::Create(outputname, true, false);
801  m_nvr->SetRingBuffer(m_outBuffer);
802  m_nvr->WriteHeader();
803  m_nvr->StreamAllocate();
804  }
805 
806  if (vidsetting == encodingType && !framecontrol && !m_avfMode &&
807  fifodir.isEmpty() && honorCutList &&
808  video_width == newWidth && video_height == newHeight)
809  {
810  copyvideo = true;
811  LOG(VB_GENERAL, LOG_INFO, "Reencoding video in 'raw' mode");
812  }
813 #endif // CONFIG_LIBMP3LAME
814 
815  if (honorCutList && !deleteMap.empty())
816  {
817  if (cleanCut)
818  {
819  // Have the player seek only part of the way
820  // through a cut, and then use the cutter to
821  // discard the rest
822  cutter = std::make_unique<Cutter>();
823  cutter->SetCutList(deleteMap, m_ctx);
824  player->SetCutList(cutter->AdjustedCutList());
825  }
826  else
827  {
828  // Have the player apply the cut list
829  player->SetCutList(deleteMap);
830  }
831  }
832 
833  player->InitForTranscode(copyaudio, copyvideo);
834  if (player->IsErrored())
835  {
836  LOG(VB_GENERAL, LOG_ERR,
837  "Unable to initialize MythPlayer for Transcode");
838  SetPlayerContext(nullptr);
839  return REENCODE_ERROR;
840  }
841 
842  // must come after InitForTranscode - which creates the VideoOutput instance
843  if (m_hlsMode && player->GetVideoOutput())
844  player->GetVideoOutput()->SetDeinterlacing(true, false, DEINT_CPU | DEINT_MEDIUM);
845 
846  MythVideoFrame frame;
847  // Do not use padding when compressing to RTjpeg or when in fifomode.
848  // The RTjpeg compressor doesn't know how to handle strides different to
849  // video width.
850  bool nonAligned = vidsetting == "RTjpeg" || !fifodir.isEmpty();
851  bool rescale = (video_width != newWidth) || (video_height != newHeight) || nonAligned;
852 
853  if (rescale)
854  {
855  if (nonAligned)
856  {
857  // Set a stride identical to actual width, to ease fifo post-conversion process.
858  // 1080i/p video is actually 1088 because of the 16x16 blocks so
859  // we have to fudge the output size here. nuvexport knows how to handle
860  // this and as of right now it is the only app that uses the fifo ability.
861  size_t newSize = MythVideoFrame::GetBufferSize(FMT_YV12,
862  video_width, video_height == 1080 ? 1088 : video_height, 0 /* aligned */);
863  uint8_t* newbuffer = MythVideoFrame::GetAlignedBuffer(newSize);
864  if (!newbuffer)
865  return REENCODE_ERROR;
866  frame.Init(FMT_YV12, newbuffer, newSize, video_width, video_height, nullptr, 0);
867  }
868  else
869  {
870  frame.Init(FMT_YV12, newWidth, newHeight);
871  }
872  }
873 
874  if (!fifodir.isEmpty())
875  {
876  AudioPlayer *aplayer = player->GetAudio();
877  const char *audio_codec_name {nullptr};
878 
879  switch(aplayer->GetCodec())
880  {
881  case AV_CODEC_ID_AC3:
882  audio_codec_name = "ac3";
883  break;
884  case AV_CODEC_ID_EAC3:
885  audio_codec_name = "eac3";
886  break;
887  case AV_CODEC_ID_DTS:
888  audio_codec_name = "dts";
889  break;
890  case AV_CODEC_ID_TRUEHD:
891  audio_codec_name = "truehd";
892  break;
893  case AV_CODEC_ID_MP3:
894  audio_codec_name = "mp3";
895  break;
896  case AV_CODEC_ID_MP2:
897  audio_codec_name = "mp2";
898  break;
899  case AV_CODEC_ID_AAC:
900  audio_codec_name = "aac";
901  break;
902  case AV_CODEC_ID_AAC_LATM:
903  audio_codec_name = "aac_latm";
904  break;
905  default:
906  audio_codec_name = "unknown";
907  }
908 
909  if (!arb->m_passthru)
910  audio_codec_name = "raw";
911 
912  // If cutlist is used then get info on first uncut frame
913  if (honorCutList && fifo_info)
914  {
915  bool is_key = false;
916  int did_ff = 0;
917  player->TranscodeGetNextFrame(did_ff, is_key, true);
918 
919  QSize buf_size2 = player->GetVideoBufferSize();
920  video_width = buf_size2.width();
921  video_height = buf_size2.height();
922  video_aspect = player->GetVideoAspect();
923  video_frame_rate = player->GetFrameRate();
924  }
925 
926  // Display details of the format of the fifo data.
927  LOG(VB_GENERAL, LOG_INFO,
928  QString("FifoVideoWidth %1").arg(video_width));
929  LOG(VB_GENERAL, LOG_INFO,
930  QString("FifoVideoHeight %1").arg(video_height));
931  LOG(VB_GENERAL, LOG_INFO,
932  QString("FifoVideoAspectRatio %1").arg(video_aspect));
933  LOG(VB_GENERAL, LOG_INFO,
934  QString("FifoVideoFrameRate %1").arg(video_frame_rate));
935  LOG(VB_GENERAL, LOG_INFO,
936  QString("FifoAudioFormat %1").arg(audio_codec_name));
937  LOG(VB_GENERAL, LOG_INFO,
938  QString("FifoAudioChannels %1").arg(arb->m_channels));
939  LOG(VB_GENERAL, LOG_INFO,
940  QString("FifoAudioSampleRate %1").arg(arb->m_eff_audiorate));
941 
942  if(fifo_info)
943  {
944  // Request was for just the format of fifo data, not for
945  // the actual transcode, so stop here.
946  unlink(outputname.toLocal8Bit().constData());
947  SetPlayerContext(nullptr);
948  return REENCODE_OK;
949  }
950 
951  QString audfifo = fifodir + QString("/audout");
952  QString vidfifo = fifodir + QString("/vidout");
953  int audio_size = arb->m_eff_audiorate * arb->m_bytes_per_frame;
954  // framecontrol is true if we want to enforce fifo sync.
955  if (framecontrol)
956  LOG(VB_GENERAL, LOG_INFO, "Enforcing sync on fifos");
957  m_fifow = new MythFIFOWriter(2, framecontrol);
958 
959  if (!m_fifow->FIFOInit(0, QString("video"), vidfifo, frame.m_bufferSize, 50) ||
960  !m_fifow->FIFOInit(1, QString("audio"), audfifo, audio_size, 25))
961  {
962  LOG(VB_GENERAL, LOG_ERR,
963  "Error initializing fifo writer. Aborting");
964  unlink(outputname.toLocal8Bit().constData());
965  SetPlayerContext(nullptr);
966  return REENCODE_ERROR;
967  }
968  LOG(VB_GENERAL, LOG_INFO,
969  QString("Video %1x%2@%3fps Audio rate: %4")
970  .arg(video_width).arg(video_height)
971  .arg(video_frame_rate)
972  .arg(arb->m_eff_audiorate));
973  LOG(VB_GENERAL, LOG_INFO, "Created fifos. Waiting for connection.");
974  }
975 
976 #if CONFIG_LIBMP3LAME
977  bool forceKeyFrames = (m_fifow == nullptr) ? framecontrol : false;
978  bool writekeyframe = true;
979  long lastKeyFrame = 0;
980  int num_keyframes = 0;
981 #endif
982 
983  frm_dir_map_t::iterator dm_iter;
984 
985  int did_ff = 0;
986 
987  long curFrameNum = 0;
988  frame.m_frameNumber = 1;
989  long totalAudio = 0;
990  int dropvideo = 0;
991  // timecode of the last read video frame in input time
992  std::chrono::milliseconds lasttimecode = 0ms;
993  // timecode of the last write video frame in input or output time
994  std::chrono::milliseconds lastWrittenTime = 0ms;
995  // delta between the same video frame in input and output due to applying the cut list
996  std::chrono::milliseconds timecodeOffset = 0ms;
997 
998  float rateTimeConv = arb->m_eff_audiorate / 1000.0F;
999  float vidFrameTime = 1000.0F / video_frame_rate;
1000  auto vidFrameTimeMs = millisecondsFromFloat(vidFrameTime);
1001  int wait_recover = 0;
1002  MythVideoOutput *videoOutput = player->GetVideoOutput();
1003  bool is_key = false;
1004  bool first_loop = true;
1005  AVFrame imageIn;
1006  AVFrame imageOut;
1007  struct SwsContext *scontext = nullptr;
1008 
1009  if (m_fifow)
1010  LOG(VB_GENERAL, LOG_INFO, "Dumping Video and Audio data to fifos");
1011  else if (copyaudio)
1012  LOG(VB_GENERAL, LOG_INFO, "Copying Audio while transcoding Video");
1013  else if (m_hlsMode)
1014  LOG(VB_GENERAL, LOG_INFO, "Transcoding for HTTP Live Streaming");
1015  else if (m_avfMode)
1016  LOG(VB_GENERAL, LOG_INFO, "Transcoding to libavformat container");
1017  else
1018  LOG(VB_GENERAL, LOG_INFO, "Transcoding Video and Audio");
1019 
1020  auto *videoBuffer =
1021  new VideoDecodeBuffer(player, videoOutput, honorCutList);
1022  MThreadPool::globalInstance()->start(videoBuffer, "VideoDecodeBuffer");
1023 
1024  QElapsedTimer flagTime;
1025  flagTime.start();
1026 
1027  if (cutter)
1028  cutter->Activate(vidFrameTime * rateTimeConv, total_frame_count);
1029 
1030  bool stopSignalled = false;
1031  MythVideoFrame *lastDecode = nullptr;
1032 
1033  if (hls)
1034  {
1036  hls->UpdateStatusMessage("Transcoding");
1037  }
1038 
1039  while ((!stopSignalled) &&
1040  (lastDecode = videoBuffer->GetFrame(did_ff, is_key)))
1041  {
1042  if (first_loop)
1043  {
1044  copyaudio = player->GetRawAudioState();
1045  first_loop = false;
1046  }
1047 
1048  float new_aspect = lastDecode->m_aspect;
1049 
1050  if (cutter)
1051  cutter->NewFrame(lastDecode->m_frameNumber);
1052 
1053 // frame timecode is on input time base
1054  frame.m_timecode = lastDecode->m_timecode;
1055 
1056  // if the timecode jumps backwards just use the last frame's timecode plus the duration of a frame
1057  if (frame.m_timecode < lasttimecode)
1058  frame.m_timecode = lasttimecode + vidFrameTimeMs;
1059 
1060  if (m_fifow)
1061  {
1062  MythAVUtil::FillAVFrame(&imageIn, lastDecode);
1063  MythAVUtil::FillAVFrame(&imageOut, &frame);
1064 
1065  scontext = sws_getCachedContext(scontext,
1066  lastDecode->m_width, lastDecode->m_height, MythAVUtil::FrameTypeToPixelFormat(lastDecode->m_type),
1068  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1069  // Typically, wee aren't rescaling per say, we're just correcting the stride set by the decoder.
1070  // However, it allows to properly handle recordings that see their resolution change half-way.
1071  sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1072  lastDecode->m_height, imageOut.data, imageOut.linesize);
1073 
1074  totalAudio += arb->GetSamples(frame.m_timecode);
1075  std::chrono::milliseconds audbufTime = millisecondsFromFloat(totalAudio / rateTimeConv);
1076  std::chrono::milliseconds auddelta = frame.m_timecode - audbufTime;
1077  std::chrono::milliseconds vidTime = millisecondsFromFloat(curFrameNum * vidFrameTime);
1078  std::chrono::milliseconds viddelta = frame.m_timecode - vidTime;
1079  std::chrono::milliseconds delta = viddelta - auddelta;
1080  std::chrono::milliseconds absdelta = std::chrono::abs(delta);
1081  if (absdelta < 500ms && absdelta >= vidFrameTimeMs)
1082  {
1083  QString msg = QString("Audio is %1ms %2 video at # %3: "
1084  "auddelta=%4, viddelta=%5")
1085  .arg(absdelta.count())
1086  .arg(((delta > 0ms) ? "ahead of" : "behind"))
1087  .arg((int)curFrameNum)
1088  .arg(auddelta.count())
1089  .arg(viddelta.count());
1090  LOG(VB_GENERAL, LOG_INFO, msg);
1091  dropvideo = (delta > 0ms) ? 1 : -1;
1092  wait_recover = 0;
1093  }
1094  else if (delta >= 500ms && delta < 10s)
1095  {
1096  if (wait_recover == 0)
1097  {
1098  dropvideo = 5;
1099  wait_recover = 6;
1100  }
1101  else if (wait_recover == 1)
1102  {
1103  // Video is badly lagging. Try to catch up.
1104  int count = 0;
1105  while (delta > vidFrameTimeMs)
1106  {
1107  if (!cutter || !cutter->InhibitDummyFrame())
1108  m_fifow->FIFOWrite(0, frame.m_buffer, frame.m_bufferSize);
1109 
1110  count++;
1111  delta -= vidFrameTimeMs;
1112  }
1113  QString msg = QString("Added %1 blank video frames")
1114  .arg(count);
1115  LOG(VB_GENERAL, LOG_INFO, msg);
1116  curFrameNum += count;
1117  dropvideo = 0;
1118  wait_recover = 0;
1119  }
1120  else
1121  {
1122  wait_recover--;
1123  }
1124  }
1125  else
1126  {
1127  dropvideo = 0;
1128  wait_recover = 0;
1129  }
1130 
1131 #if 0
1132  int buflen = (int)(arb->audiobuffer_len / rateTimeConv);
1133  LOG(VB_GENERAL, LOG_DEBUG,
1134  QString("%1: video time: %2 audio time: %3 "
1135  "buf: %4 exp: %5 delta: %6")
1136  .arg(curFrameNum) .arg(frame.m_timecode.count())
1137  .arg(arb->last_audiotime) .arg(buflen) .arg(audbufTime.count())
1138  .arg(delta.count()));
1139 #endif
1140  AudioBuffer *ab = nullptr;
1141  while ((ab = arb->GetData(frame.m_timecode)) != nullptr)
1142  {
1143  if (!cutter ||
1144  !cutter->InhibitUseAudioFrames(ab->m_frames, &totalAudio))
1145  m_fifow->FIFOWrite(1, ab->data(), ab->size());
1146 
1147  delete ab;
1148  }
1149 
1150  if (dropvideo < 0)
1151  {
1152  if (cutter && cutter->InhibitDropFrame())
1153  m_fifow->FIFOWrite(0, frame.m_buffer, frame.m_bufferSize);
1154 
1155  LOG(VB_GENERAL, LOG_INFO, "Dropping video frame");
1156  dropvideo++;
1157  curFrameNum--;
1158  }
1159  else
1160  {
1161  if (!cutter || !cutter->InhibitUseVideoFrame())
1162  m_fifow->FIFOWrite(0, frame.m_buffer, frame.m_bufferSize);
1163 
1164  if (dropvideo)
1165  {
1166  if (!cutter || !cutter->InhibitDummyFrame())
1167  m_fifow->FIFOWrite(0, frame.m_buffer, frame.m_bufferSize);
1168 
1169  curFrameNum++;
1170  dropvideo--;
1171  }
1172  }
1173  videoOutput->DoneDisplayingFrame(lastDecode);
1174  player->GetCC608Reader()->FlushTxtBuffers();
1175  lasttimecode = frame.m_timecode;
1176  }
1177  else if (copyaudio)
1178  {
1179 #if CONFIG_LIBMP3LAME
1180  // Encoding from NuppelVideo to NuppelVideo with MP3 audio
1181  // So let's not decode/reencode audio
1182  if (!player->GetRawAudioState())
1183  {
1184  // The Raw state changed during decode. This is not good
1185  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, MythPlayer "
1186  "is not in raw audio mode.");
1187 
1188  unlink(outputname.toLocal8Bit().constData());
1189  SetPlayerContext(nullptr);
1190  if (videoBuffer)
1191  videoBuffer->stop();
1192  if (hls)
1193  {
1195  hls->UpdateStatusMessage("Transcoding Errored");
1196  }
1197  return REENCODE_ERROR;
1198  }
1199 
1200  if (forceKeyFrames)
1201  writekeyframe = true;
1202  else
1203  {
1204  writekeyframe = is_key;
1205  if (writekeyframe)
1206  {
1207  // Currently, we don't create new sync frames,
1208  // (though we do create new 'I' frames), so we mark
1209  // the key-frames before deciding whether we need a
1210  // new 'I' frame.
1211 
1212  //need to correct the frame# and timecode here
1213  // Question: Is it necessary to change the timecodes?
1214  long sync_offset = 0;
1215  m_nvr->UpdateSeekTable(num_keyframes, sync_offset);
1216  ReencoderAddKFA(curFrameNum, lastKeyFrame, num_keyframes);
1217  num_keyframes++;
1218  lastKeyFrame = curFrameNum;
1219 
1220  if (did_ff)
1221  did_ff = 0;
1222  }
1223  }
1224 
1225  if (did_ff == 1)
1226  {
1227  timecodeOffset += (frame.m_timecode - lasttimecode - vidFrameTimeMs);
1228  }
1229  lasttimecode = frame.m_timecode;
1230 // from here on the timecode is on the output time base
1231  frame.m_timecode -= timecodeOffset;
1232 
1233  if ((did_ff != 0) || !copyvideo)
1234  {
1235  if (video_aspect != new_aspect)
1236  {
1237  video_aspect = new_aspect;
1238  m_nvr->SetNewVideoParams(video_aspect);
1239  }
1240 
1241  QSize buf_size3 = player->GetVideoBufferSize();
1242 
1243  if (video_width != buf_size3.width() ||
1244  video_height != buf_size3.height())
1245  {
1246  video_width = buf_size3.width();
1247  video_height = buf_size3.height();
1248 
1249  LOG(VB_GENERAL, LOG_INFO,
1250  QString("Resizing from %1x%2 to %3x%4")
1251  .arg(video_width).arg(video_height)
1252  .arg(newWidth).arg(newHeight));
1253 
1254  }
1255 
1256  if (did_ff == 1)
1257  {
1258  // Create a new 'I' frame if we just processed a cut.
1259  did_ff = 2;
1260  writekeyframe = true;
1261  }
1262 
1263  if (rescale)
1264  {
1265  MythAVUtil::FillAVFrame(&imageIn, lastDecode);
1266  MythAVUtil::FillAVFrame(&imageOut, &frame);
1267 
1268  int bottomBand = (lastDecode->m_height == 1088) ? 8 : 0;
1269  scontext = sws_getCachedContext(scontext,
1270  lastDecode->m_width, lastDecode->m_height, MythAVUtil::FrameTypeToPixelFormat(lastDecode->m_type),
1272  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1273 
1274  sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1275  lastDecode->m_height - bottomBand,
1276  imageOut.data, imageOut.linesize);
1277  }
1278 
1279  m_nvr->WriteVideo(rescale ? &frame : lastDecode, true, writekeyframe);
1280  }
1281  player->GetCC608Reader()->FlushTxtBuffers();
1282 #else
1283  LOG(VB_GENERAL, LOG_ERR,
1284  "Not compiled with libmp3lame support. Should never get here");
1285  return REENCODE_ERROR;
1286 #endif // CONFIG_LIBMP3LAME
1287  }
1288  else
1289  {
1290  if (did_ff == 1)
1291  {
1292  did_ff = 2;
1293  timecodeOffset += (frame.m_timecode - lasttimecode -
1294  millisecondsFromFloat(vidFrameTime));
1295  }
1296 
1297  if (video_aspect != new_aspect)
1298  {
1299  video_aspect = new_aspect;
1300 #if CONFIG_LIBMP3LAME
1301  if (m_nvr)
1302  m_nvr->SetNewVideoParams(video_aspect);
1303 #endif
1304  }
1305 
1306 
1307  QSize buf_size4 = player->GetVideoBufferSize();
1308 
1309  if (video_width != buf_size4.width() ||
1310  video_height != buf_size4.height())
1311  {
1312  video_width = buf_size4.width();
1313  video_height = buf_size4.height();
1314 
1315  LOG(VB_GENERAL, LOG_INFO,
1316  QString("Resizing from %1x%2 to %3x%4")
1317  .arg(video_width).arg(video_height)
1318  .arg(newWidth).arg(newHeight));
1319  }
1320 
1321  if (rescale)
1322  {
1323  MythAVUtil::FillAVFrame(&imageIn, lastDecode);
1324  MythAVUtil::FillAVFrame(&imageOut, &frame);
1325 
1326  int bottomBand = (lastDecode->m_height == 1088) ? 8 : 0;
1327  scontext = sws_getCachedContext(scontext,
1328  lastDecode->m_width, lastDecode->m_height, MythAVUtil::FrameTypeToPixelFormat(lastDecode->m_type),
1330  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1331 
1332  sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1333  lastDecode->m_height - bottomBand,
1334  imageOut.data, imageOut.linesize);
1335  }
1336 
1337  // audio is fully decoded, so we need to reencode it
1338  AudioBuffer *ab = nullptr;
1339  while ((ab = arb->GetData(lastWrittenTime)) != nullptr)
1340  {
1341  auto *buf = (unsigned char *)ab->data();
1342  if (m_avfMode)
1343  {
1344  if (did_ff != 1)
1345  {
1346  std::chrono::milliseconds tc = ab->m_time - timecodeOffset;
1347  avfw->WriteAudioFrame(buf, audioFrame, tc);
1348 
1349  if (avfw2)
1350  {
1351  if ((avfw2->GetTimecodeOffset() == -1ms) &&
1352  (avfw->GetTimecodeOffset() != -1ms))
1353  {
1354  avfw2->SetTimecodeOffset(
1355  avfw->GetTimecodeOffset());
1356  }
1357 
1358  tc = ab->m_time - timecodeOffset;
1359  avfw2->WriteAudioFrame(buf, audioFrame, tc);
1360  }
1361 
1362  ++audioFrame;
1363  }
1364  }
1365 #if CONFIG_LIBMP3LAME
1366  else
1367  {
1368  m_nvr->SetOption("audioframesize", ab->size());
1369  m_nvr->WriteAudio(buf, audioFrame++,
1370  (ab->m_time - timecodeOffset));
1371  if (m_nvr->IsErrored())
1372  {
1373  LOG(VB_GENERAL, LOG_ERR,
1374  "Transcode: Encountered irrecoverable error in "
1375  "NVR::WriteAudio");
1376  SetPlayerContext(nullptr);
1377  if (videoBuffer)
1378  videoBuffer->stop();
1379  delete ab;
1380  return REENCODE_ERROR;
1381  }
1382  }
1383 #endif
1384  delete ab;
1385  }
1386 
1387  if (!m_avfMode)
1388  {
1389 #if CONFIG_LIBMP3LAME
1390  player->GetCC608Reader()->
1391  TranscodeWriteText(&TranscodeWriteText, (void *)(m_nvr));
1392 #else
1393  LOG(VB_GENERAL, LOG_ERR,
1394  "Not compiled with libmp3lame support");
1395  return REENCODE_ERROR;
1396 #endif
1397  }
1398  lasttimecode = frame.m_timecode;
1399  frame.m_timecode -= timecodeOffset;
1400 
1401  if (m_avfMode)
1402  {
1403  if (halfFramerate && !skippedLastFrame)
1404  {
1405  skippedLastFrame = true;
1406  }
1407  else
1408  {
1409  skippedLastFrame = false;
1410 
1411  if ((hls) &&
1412  (avfw->GetFramesWritten()) &&
1413  (hlsSegmentFrames > hlsSegmentSize) &&
1414  (avfw->NextFrameIsKeyFrame()))
1415  {
1416  hls->AddSegment();
1417  avfw->ReOpen(hls->GetCurrentFilename());
1418 
1419  if (avfw2)
1420  avfw2->ReOpen(hls->GetCurrentFilename(true));
1421 
1422  hlsSegmentFrames = 0;
1423  }
1424 
1425  if (avfw->WriteVideoFrame(rescale ? &frame : lastDecode) > 0)
1426  {
1427  lastWrittenTime = frame.m_timecode + timecodeOffset;
1428  if (hls)
1429  ++hlsSegmentFrames;
1430  }
1431 
1432  }
1433  }
1434 #if CONFIG_LIBMP3LAME
1435  else
1436  {
1437  if (forceKeyFrames)
1438  m_nvr->WriteVideo(rescale ? &frame : lastDecode, true, true);
1439  else
1440  m_nvr->WriteVideo(rescale ? &frame : lastDecode);
1441  lastWrittenTime = frame.m_timecode + timecodeOffset;
1442  }
1443 #endif
1444  }
1445  if (MythDate::current() > statustime)
1446  {
1447  if (m_showProgress)
1448  {
1449  LOG(VB_GENERAL, LOG_INFO,
1450  QString("Processed: %1 of %2 frames(%3 seconds)").
1451  arg(curFrameNum).arg((long)total_frame_count).
1452  arg((long)(curFrameNum / video_frame_rate)));
1453  }
1454 
1455  if (hls && hls->CheckStop())
1456  {
1458  stopSignalled = true;
1459  }
1460 
1461  statustime = MythDate::current().addSecs(5);
1462  }
1463  if (MythDate::current() > curtime)
1464  {
1465  if (honorCutList && m_proginfo && !m_avfMode &&
1467  {
1468  LOG(VB_GENERAL, LOG_NOTICE,
1469  "Transcoding aborted, cutlist updated");
1470 
1471  unlink(outputname.toLocal8Bit().constData());
1472  SetPlayerContext(nullptr);
1473  if (videoBuffer)
1474  videoBuffer->stop();
1475  return REENCODE_CUTLIST_CHANGE;
1476  }
1477 
1478  if ((jobID >= 0) || (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_INFO)))
1479  {
1481  {
1482  LOG(VB_GENERAL, LOG_NOTICE,
1483  "Transcoding STOPped by JobQueue");
1484 
1485  unlink(outputname.toLocal8Bit().constData());
1486  SetPlayerContext(nullptr);
1487  if (videoBuffer)
1488  videoBuffer->stop();
1489  if (hls)
1490  {
1492  hls->UpdateStatusMessage("Transcoding Stopped");
1493  }
1494  return REENCODE_STOPPED;
1495  }
1496 
1497  float flagFPS = 0.0;
1498  float elapsed = flagTime.elapsed() / 1000.0;
1499  if (elapsed != 0.0F)
1500  flagFPS = curFrameNum / elapsed;
1501 
1502  total_frame_count = player->GetCurrentFrameCount();
1503  int percentage = curFrameNum * 100 / total_frame_count;
1504 
1505  if (hls)
1506  hls->UpdatePercentComplete(percentage);
1507 
1508  if (jobID >= 0)
1509  {
1511  QObject::tr("%1% Completed @ %2 fps.")
1512  .arg(percentage).arg(flagFPS));
1513  }
1514  else
1515  {
1516  LOG(VB_GENERAL, LOG_INFO,
1517  QString("mythtranscode: %1% Completed @ %2 fps.")
1518  .arg(percentage).arg(flagFPS));
1519  }
1520 
1521  }
1522  curtime = MythDate::current().addSecs(20);
1523  }
1524 
1525  curFrameNum++;
1526  frame.m_frameNumber = 1 + (curFrameNum << 1);
1527 
1528  player->DiscardVideoFrame(lastDecode);
1529  }
1530 
1531  sws_freeContext(scontext);
1532 
1533  if (!m_fifow)
1534  {
1535  if (avfw)
1536  avfw->CloseFile();
1537 
1538  if (avfw2)
1539  avfw2->CloseFile();
1540 
1541  if (!m_avfMode && m_proginfo)
1542  {
1547  }
1548 
1549 #if CONFIG_LIBMP3LAME
1550  if (m_nvr)
1551  {
1552  m_nvr->WriteSeekTable();
1553  if (!m_kfaTable->empty())
1554  m_nvr->WriteKeyFrameAdjustTable(*m_kfaTable);
1555  }
1556 #endif // CONFIG_LIBMP3LAME
1557  } else {
1558  m_fifow->FIFODrain();
1559  }
1560 
1561  if (hls)
1562  {
1563  if (!stopSignalled)
1564  {
1566  hls->UpdateStatusMessage("Transcoding Completed");
1567  hls->UpdatePercentComplete(100);
1568  }
1569  else
1570  {
1572  hls->UpdateStatusMessage("Transcoding Stopped");
1573  }
1574  }
1575 
1576  if (videoBuffer)
1577  videoBuffer->stop();
1578 
1579  SetPlayerContext(nullptr);
1580 
1581  return REENCODE_OK;
1582 }
1583 
1584 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1585 
HTTPLiveStream::GetSourceFile
QString GetSourceFile(void) const
Definition: httplivestream.h:40
JobQueue::GetJobCmd
static enum JobCmds GetJobCmd(int jobID)
Definition: jobqueue.cpp:1464
MythMediaWriter::SetTimecodeOffset
void SetTimecodeOffset(std::chrono::milliseconds Offset)
Definition: mythmediawriter.cpp:99
HTTPLiveStream::GetWidth
uint16_t GetWidth(void) const
Definition: httplivestream.h:34
Cutter::Activate
void Activate(float v2a, int64_t total)
Definition: cutter.cpp:63
HTTPLiveStream::CheckStop
bool CheckStop(void)
Definition: httplivestream.cpp:799
MythMediaWriter::SetAudioFrameRate
void SetAudioFrameRate(int Rate)
Definition: mythmediawriter.cpp:84
Transcode::m_cmdContainer
QString m_cmdContainer
Definition: transcode.h:70
Cutter::InhibitDummyFrame
bool InhibitDummyFrame(void)
Definition: cutter.cpp:155
RemoteGetExistingRecorder
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)
Definition: tvremoteutil.cpp:312
MARK_KEYFRAME
@ MARK_KEYFRAME
Definition: programtypes.h:61
HTTPLiveStream::GetCurrentFilename
QString GetCurrentFilename(bool audioOnly=false, bool encoded=false) const
Definition: httplivestream.cpp:202
MythVideoOutput
Definition: mythvideoout.h:35
deletemap.h
Transcode::m_fifow
MythFIFOWriter * m_fifow
Definition: transcode.h:61
HTTPLiveStream::UpdateSizeInfo
bool UpdateSizeInfo(uint16_t width, uint16_t height, uint16_t srcwidth, uint16_t srcheight)
Definition: httplivestream.cpp:528
AudioReencodeBuffer
This class is to act as a fake audio output device to store the data for reencoding.
Definition: audioreencodebuffer.h:31
AudioPlayer
Definition: audioplayer.h:22
MARK_GOP_START
@ MARK_GOP_START
Definition: programtypes.h:60
Transcode::m_outBuffer
MythMediaBuffer * m_outBuffer
Definition: transcode.h:60
MythAVFormatWriter::ReOpen
bool ReOpen(const QString &Filename)
Definition: mythavformatwriter.cpp:412
AudioReencodeBuffer::m_eff_audiorate
int m_eff_audiorate
Definition: audioreencodebuffer.h:73
FORMAT_S16
@ FORMAT_S16
Definition: audiooutputsettings.h:27
MythMediaWriter::SetVideoCodec
void SetVideoCodec(const QString &Codec)
Definition: mythmediawriter.cpp:34
kHLSStatusRunning
@ kHLSStatusRunning
Definition: httplivestream.h:12
NuppelVideoRecorder.h
kHLSStatusCompleted
@ kHLSStatusCompleted
Definition: httplivestream.h:13
Transcode::m_keyframeDist
int m_keyframeDist
Definition: transcode.h:55
RecordingProfile::loadByGroup
virtual bool loadByGroup(const QString &name, const QString &group)
Definition: recordingprofile.cpp:1550
MythMediaWriter::SetAudioCodec
void SetAudioCodec(const QString &Codec)
Definition: mythmediawriter.cpp:69
Transcode::m_recProfile
RecordingProfile * m_recProfile
Definition: transcode.h:54
cutter.h
Transcode::Transcode
Transcode(ProgramInfo *pginfo)
Definition: transcode.cpp:52
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
mythdbcon.h
MythMediaWriter::SetAudioChannels
void SetAudioChannels(int Channels)
Definition: mythmediawriter.cpp:79
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:117
kfatable_entry::keyframe_number
int keyframe_number
Definition: format.h:136
MythMediaWriter::GetFramesWritten
long long GetFramesWritten(void) const
Definition: mythmediawriter.cpp:114
MythVideoFrame::m_width
int m_width
Definition: mythframe.h:120
Transcode::m_cmdAudioBitrate
int m_cmdAudioBitrate
Definition: transcode.h:76
MythMediaBuffer
Definition: mythmediabuffer.h:59
RecordingProfile::loadByID
virtual void loadByID(int id)
Definition: recordingprofile.cpp:1456
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythFIFOWriter
Definition: mythfifowriter.h:31
kHLSStatusStopped
@ kHLSStatusStopped
Definition: httplivestream.h:16
MythVideoFrame::Init
void Init(VideoFrameType Type, int Width, int Height, const VideoFrameTypes *RenderFormats=nullptr)
Definition: mythframe.cpp:42
httplivestream.h
kHLSStatusStopping
@ kHLSStatusStopping
Definition: httplivestream.h:15
PlayerFlags
PlayerFlags
Definition: mythplayer.h:64
HTTPLiveStream::UpdateStatus
bool UpdateStatus(HTTPLiveStreamStatus status)
Definition: httplivestream.cpp:579
MARK_UPDATED_CUT
@ MARK_UPDATED_CUT
Definition: programtypes.h:52
kfatable_entry
Definition: format.h:133
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:413
Transcode::m_cmdHeight
int m_cmdHeight
Definition: transcode.h:74
Transcode::m_hlsStreamID
int m_hlsStreamID
Definition: transcode.h:67
REENCODE_ERROR
@ REENCODE_ERROR
Definition: transcodedefs.h:8
MythMediaWriter::SetEncodingPreset
void SetEncodingPreset(const QString &Preset)
Definition: mythmediawriter.cpp:104
HTTPLiveStream::GetSegmentSize
uint16_t GetSegmentSize(void) const
Definition: httplivestream.h:44
MythFIFOWriter::FIFODrain
void FIFODrain(void)
Definition: mythfifowriter.cpp:259
jobID
int jobID
Definition: mythcommflag.cpp:80
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
JobQueue::IsJobRunning
static bool IsJobRunning(int jobType, uint chanid, const QDateTime &recstartts)
Definition: jobqueue.cpp:1085
MythMediaWriter::SetFilename
void SetFilename(const QString &FileName)
Definition: mythmediawriter.cpp:24
REENCODE_STOPPED
@ REENCODE_STOPPED
Definition: transcodedefs.h:9
Transcode::m_hlsDisableAudioOnly
bool m_hlsDisableAudioOnly
Definition: transcode.h:68
Cutter::AdjustedCutList
frm_dir_map_t AdjustedCutList() const
Definition: cutter.cpp:58
MythMediaWriter::GetAudioFrameSize
int GetAudioFrameSize(void) const
Definition: mythmediawriter.cpp:124
Transcode::m_hlsMaxSegments
int m_hlsMaxSegments
Definition: transcode.h:69
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
AudioOutput
Definition: audiooutput.h:25
AudioBuffer::m_time
std::chrono::milliseconds m_time
Definition: audioreencodebuffer.h:24
HTTPLiveStream::GetAudioBitrate
uint32_t GetAudioBitrate(void) const
Definition: httplivestream.h:37
programinfo.h
MythVideoFrame::GetBufferSize
static size_t GetBufferSize(VideoFrameType Type, int Width, int Height, int Aligned=MYTH_WIDTH_ALIGNMENT)
Definition: mythframe.cpp:412
ProgramInfo::QueryMarkupFlag
bool QueryMarkupFlag(MarkTypes type) const
Returns true iff the speficied mark type is set on frame 0.
Definition: programinfo.cpp:3766
Transcode::m_cmdVideoCodec
QString m_cmdVideoCodec
Definition: transcode.h:72
AudioReencodeBuffer::GetData
AudioBuffer * GetData(std::chrono::milliseconds time)
Definition: audioreencodebuffer.cpp:202
Transcode::GetPlayer
MythPlayer * GetPlayer(void)
Definition: transcode.h:50
hardwareprofile.scan.profile
profile
Definition: scan.py:97
AudioReencodeBuffer::m_bytes_per_frame
int m_bytes_per_frame
Definition: audioreencodebuffer.h:72
MythMediaWriter::SetWidth
void SetWidth(int Width)
Definition: mythmediawriter.cpp:44
MythAVFormatWriter::OpenFile
bool OpenFile(void) override
Definition: mythavformatwriter.cpp:133
JobQueue::ChangeJobComment
static bool ChangeJobComment(int jobID, const QString &comment="")
Definition: jobqueue.cpp:1009
FORMAT_NONE
@ FORMAT_NONE
Definition: audiooutputsettings.h:25
HTTPLiveStream::InitForWrite
bool InitForWrite(void)
Definition: httplivestream.cpp:167
MythVideoFrame::m_timecode
std::chrono::milliseconds m_timecode
Definition: mythframe.h:130
Transcode::m_cmdAudioCodec
QString m_cmdAudioCodec
Definition: transcode.h:71
Cutter::NewFrame
void NewFrame(int64_t currentFrame)
Definition: cutter.cpp:73
kTranscoderInUseID
const QString kTranscoderInUseID
Definition: programtypes.cpp:24
mythtranscodeplayer.h
MythAVFormatWriter::NextFrameIsKeyFrame
bool NextFrameIsKeyFrame(void)
Definition: mythavformatwriter.cpp:200
HTTPLiveStream::UpdateStatusMessage
bool UpdateStatusMessage(const QString &message)
Definition: httplivestream.cpp:617
MythMediaWriter::SetEncodingTune
void SetEncodingTune(const QString &Tune)
Definition: mythmediawriter.cpp:109
ProgramInfo::QueryCutList
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
Definition: programinfo.cpp:3475
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:128
MythFIFOWriter::FIFOInit
bool FIFOInit(uint Id, const QString &Desc, const QString &Name, long Size, int NumBufs)
Definition: mythfifowriter.cpp:109
AudioReencodeBuffer::m_audioFrameSize
int m_audioFrameSize
Definition: audioreencodebuffer.h:76
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:79
MythMediaWriter::SetAudioBitrate
void SetAudioBitrate(int Bitrate)
Definition: mythmediawriter.cpp:74
HTTPLiveStream::GetBitrate
uint32_t GetBitrate(void) const
Definition: httplivestream.h:36
AudioBuffer::size
int size(void) const
Definition: audioreencodebuffer.h:18
MythVideoFrame::m_bufferSize
size_t m_bufferSize
Definition: mythframe.h:123
ProgramInfo::ClearMarkupFlag
void ClearMarkupFlag(MarkTypes type) const
Definition: programinfo.h:651
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:23
HTTPLiveStream::GetAudioOnlyBitrate
uint32_t GetAudioOnlyBitrate(void) const
Definition: httplivestream.h:38
REENCODE_CUTLIST_CHANGE
@ REENCODE_CUTLIST_CHANGE
Definition: transcodedefs.h:6
MythAVFormatWriter::CloseFile
bool CloseFile(void) override
Definition: mythavformatwriter.cpp:185
jobqueue.h
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
AudioBuffer::data
char * data(void) const
Definition: audioreencodebuffer.h:17
mythavformatwriter.h
kNoITV
@ kNoITV
Definition: mythplayer.h:75
HTTPLiveStream::AddSegment
bool AddSegment(void)
Definition: httplivestream.cpp:306
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
HTTPLiveStream::GetHeight
uint16_t GetHeight(void) const
Definition: httplivestream.h:35
Cutter::InhibitDropFrame
bool InhibitDropFrame(void)
Definition: cutter.cpp:167
DEINT_CPU
@ DEINT_CPU
Definition: mythframe.h:72
MythMediaWriter::SetKeyFrameDist
void SetKeyFrameDist(int Dist)
Definition: mythmediawriter.cpp:64
Cutter::InhibitUseAudioFrames
bool InhibitUseAudioFrames(int64_t frames, long *totalAudio)
Definition: cutter.cpp:120
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
Transcode::m_cmdBitrate
int m_cmdBitrate
Definition: transcode.h:75
MythAVFormatWriter::WriteVideoFrame
int WriteVideoFrame(MythVideoFrame *Frame) override
Definition: mythavformatwriter.cpp:206
HTTPLiveStream::UpdatePercentComplete
bool UpdatePercentComplete(int percent)
Definition: httplivestream.cpp:642
MARK_GOP_BYFRAME
@ MARK_GOP_BYFRAME
Definition: programtypes.h:63
MythFIFOWriter::FIFOWrite
void FIFOWrite(uint Id, void *Buffer, long Size)
Definition: mythfifowriter.cpp:214
Transcode::GetProfile
bool GetProfile(const QString &profileName, const QString &encodingType, int height, int frameRate)
Definition: transcode.cpp:81
tvremoteutil.h
DecoderBase::GetVideoAspect
float GetVideoAspect(void) const
Definition: decoderbase.h:183
Transcode::m_recorderOptions
QString m_recorderOptions
Definition: transcode.h:64
Transcode::m_proginfo
ProgramInfo * m_proginfo
Definition: transcode.h:53
mthreadpool.h
DEINT_MEDIUM
@ DEINT_MEDIUM
Definition: mythframe.h:70
HTTPLiveStream::GetStreamID
int GetStreamID(void) const
Definition: httplivestream.h:33
AudioBuffer::m_frames
int m_frames
Definition: audioreencodebuffer.h:23
MARK_DURATION_MS
@ MARK_DURATION_MS
Definition: programtypes.h:73
MythMediaWriter::SetThreadCount
void SetThreadCount(int Count)
Definition: mythmediawriter.cpp:94
kVideoIsNull
@ kVideoIsNull
Definition: mythplayer.h:73
MythMediaWriter::SetContainer
void SetContainer(const QString &Cont)
Definition: mythmediawriter.cpp:29
Transcode::m_avfMode
bool m_avfMode
Definition: transcode.h:65
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
AudioPlayer::GetCodec
AVCodecID GetCodec(void) const
Definition: audioplayer.h:58
VideoDecodeBuffer
Definition: videodecodebuffer.h:16
mythcorecontext.h
Transcode::m_kfaTable
KFATable * m_kfaTable
Definition: transcode.h:62
transcode.h
MythMediaWriter::GetTimecodeOffset
std::chrono::milliseconds GetTimecodeOffset(void) const
Definition: mythmediawriter.cpp:119
MythVideoFrame::m_type
VideoFrameType m_type
Definition: mythframe.h:118
ProgramInfo::QueryIsEditing
bool QueryIsEditing(void) const
Queries "recorded" table for its "editing" field and returns true if it is set to true.
Definition: programinfo.cpp:3114
JOB_STOP
@ JOB_STOP
Definition: jobqueue.h:54
ProgramInfo::ClearPositionMap
void ClearPositionMap(MarkTypes type) const
Definition: programinfo.cpp:3830
kHLSStatusStarting
@ kHLSStatusStarting
Definition: httplivestream.h:11
AudioReencodeBuffer::m_passthru
bool m_passthru
Definition: audioreencodebuffer.h:75
audiooutput.h
REENCODE_OK
@ REENCODE_OK
Definition: transcodedefs.h:7
MythAVUtil::FrameTypeToPixelFormat
static AVPixelFormat FrameTypeToPixelFormat(VideoFrameType Type)
Definition: mythavutil.cpp:28
Transcode::~Transcode
~Transcode() override
Definition: transcode.cpp:58
mythavutil.h
Transcode::m_hlsMode
bool m_hlsMode
Definition: transcode.h:66
MythMediaWriter::SetHeight
void SetHeight(int Height)
Definition: mythmediawriter.cpp:49
MythMediaWriter::SetFramerate
void SetFramerate(double Rate)
Definition: mythmediawriter.cpp:59
PlayerContext
Definition: playercontext.h:49
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:99
MythMediaBuffer::GetLastError
QString GetLastError(void) const
Definition: mythmediabuffer.cpp:1770
AudioBuffer
Definition: audioreencodebuffer.h:9
videodecodebuffer.h
MythVideoFrame::m_height
int m_height
Definition: mythframe.h:121
audioreencodebuffer.h
kTrackTypeAudio
@ kTrackTypeAudio
Definition: decoderbase.h:30
Transcode::m_ctx
PlayerContext * m_ctx
Definition: transcode.h:59
StandardSetting
Definition: standardsettings.h:29
MythMediaWriter::SetAudioFormat
void SetAudioFormat(AudioFormat Format)
Definition: mythmediawriter.cpp:89
MythVideoFrame::GetAlignedBuffer
static uint8_t * GetAlignedBuffer(size_t Size)
Definition: mythframe.cpp:430
recordingprofile.h
Transcode::m_showProgress
bool m_showProgress
Definition: transcode.h:63
MythMediaWriter::SetAspect
void SetAspect(float Aspect)
Definition: mythmediawriter.cpp:54
RecordingProfile
Definition: recordingprofile.h:41
LOC
#define LOC
Definition: transcode.cpp:50
MythVideoFrame
Definition: mythframe.h:87
exitcodes.h
Transcode::SetPlayerContext
void SetPlayerContext(PlayerContext *player_ctx)
Definition: transcode.cpp:142
Transcode::m_cmdWidth
int m_cmdWidth
Definition: transcode.h:73
Cutter::InhibitUseVideoFrame
bool InhibitUseVideoFrame(void)
Definition: cutter.cpp:100
Cutter::SetCutList
void SetCutList(frm_dir_map_t &deleteMap, PlayerContext *ctx)
Definition: cutter.cpp:11
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:307
MythMediaWriter::SetVideoBitrate
void SetVideoBitrate(int Bitrate)
Definition: mythmediawriter.cpp:39
build_compdb.options
options
Definition: build_compdb.py:11
Transcode::ReencoderAddKFA
void ReencoderAddKFA(long curframe, long lastkey, long num_keyframes)
Definition: transcode.cpp:69
AudioReencodeBuffer::m_channels
int m_channels
Definition: audioreencodebuffer.h:71
kHLSStatusErrored
@ kHLSStatusErrored
Definition: httplivestream.h:14
kfatable_entry::adjust
int adjust
Definition: format.h:135
MythAVUtil::FillAVFrame
static int FillAVFrame(AVFrame *Frame, const MythVideoFrame *From, AVPixelFormat Fmt=AV_PIX_FMT_NONE)
Initialise AVFrame with content from MythVideoFrame.
Definition: mythavutil.cpp:199
MythVideoFrame::m_aspect
float m_aspect
Definition: mythframe.h:126
AudioReencodeBuffer::GetSamples
long long GetSamples(std::chrono::milliseconds time)
Definition: audioreencodebuffer.cpp:220
MythAVFormatWriter::Init
bool Init(void) override
Definition: mythavformatwriter.cpp:58
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:342
DecoderBase
Definition: decoderbase.h:121
REENCODE_MPEG2TRANS
@ REENCODE_MPEG2TRANS
Definition: transcodedefs.h:5
MythAVFormatWriter::WriteAudioFrame
int WriteAudioFrame(unsigned char *Buffer, int FrameNumber, std::chrono::milliseconds &Timecode) override
Definition: mythavformatwriter.cpp:289
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
millisecondsFromFloat
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:91
MythVideoFrame::m_buffer
uint8_t * m_buffer
Definition: mythframe.h:119
MythTranscodePlayer
Definition: mythtranscodeplayer.h:7
MythVideoOutput::DoneDisplayingFrame
virtual void DoneDisplayingFrame(MythVideoFrame *Frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
Definition: mythvideoout.cpp:420
NuppelVideoRecorder
Definition: NuppelVideoRecorder.h:70
Transcode::TranscodeFile
int TranscodeFile(const QString &inputname, const QString &outputname, const QString &profileName, bool honorCutList, bool framecontrol, int jobID, const QString &fifodir, bool fifo_info, bool cleanCut, frm_dir_map_t &deleteMap, int AudioTrackNo, bool passthru=false)
Definition: transcode.cpp:195