]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Transcoding: Add audio bitrate limiter, video quantizer, tweaking of default encoder...
authorJoakim Gissberg <joakim@gissberg.nu>
Mon, 12 Jan 2015 11:42:52 +0000 (12:42 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 13 Jan 2015 17:51:33 +0000 (18:51 +0100)
src/plumbing/transcoding.c
src/plumbing/transcoding.h
src/profile.c

index 271d16aaeae0bc4f5cd0b4b7c72ec307fcffadc8..5624ffa0199bf746c6c5267c4735fa7704e61860 100644 (file)
@@ -542,13 +542,16 @@ transcoder_stream_audio(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt)
       }
     }
 
+    // User specified streaming profile audio bitrate limiter.
+    if (t->t_props.tp_abitrate >=16) {
+      octx->bit_rate       = t->t_props.tp_abitrate * 1000;
+    }
+
     switch (ts->ts_type) {
     case SCT_MPEG2AUDIO:
-      octx->bit_rate       = 128000;
       break;
 
     case SCT_AAC:
-      octx->bit_rate       = 128000;
       octx->flags         |= CODEC_FLAG_BITEXACT;
       break;
 
@@ -587,10 +590,10 @@ transcoder_stream_audio(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt)
       // Convert audio
       tvhtrace("transcode", "%04X: converting audio", shortid(t));
 
-      tvhtrace("transcode", "%04X: IN : channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%d",
+      tvhinfo("transcode", "%04X: IN : channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%d",
                shortid(t), ictx->channels, ictx->channel_layout, ictx->sample_rate,
                ictx->sample_fmt, ictx->bit_rate);
-      tvhtrace("transcode", "%04X: OUT: channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%d",
+      tvhinfo("transcode", "%04X: OUT: channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%d",
                shortid(t), octx->channels, octx->channel_layout, octx->sample_rate,
                octx->sample_fmt, octx->bit_rate);
 
@@ -1043,7 +1046,7 @@ transcoder_stream_video(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt)
 
       } else {
         octx->bit_rate       = t->t_props.tp_vbitrate * 1000;
-        octx->rc_max_rate    = octx->bit_rate * 1.05;
+        octx->rc_max_rate    = octx->bit_rate;
       }
 
       octx->rc_buffer_size = 2 * octx->rc_max_rate;
@@ -1053,14 +1056,19 @@ transcoder_stream_video(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt)
       octx->codec_id       = AV_CODEC_ID_VP8;
       octx->pix_fmt        = PIX_FMT_YUV420P;
 
-      av_dict_set(&opts, "quality",  "realtime", 0);
+      av_dict_set(&opts, "quality",  "good", 0);
 
       if (t->t_props.tp_vbitrate == 0) {
         octx->qmin = 10;
         octx->qmax = 20;
-      } else {
+      }
+
+      // Stream profile vbitrate 1-63 is used for user specified qmin quantizer (CRF mode).
+      if (t->t_props.tp_vbitrate >0 && t->t_props.tp_vbitrate <64) {
+        octx->qmin = t->t_props.tp_vbitrate; // qmax = 63 as default.
+      } else { // CBR mode.
         octx->bit_rate       = t->t_props.tp_vbitrate * 1000;
-        octx->rc_max_rate    = octx->bit_rate * 1.05;
+        octx->rc_max_rate    = octx->bit_rate;
       }
 
       octx->rc_buffer_size = 8 * 1024 * 224;
@@ -1088,16 +1096,29 @@ transcoder_stream_video(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt)
       // Recommended default: -qmax 51
       // octx->qmax = 30;
 
-      av_dict_set(&opts, "preset",  "medium", 0);
-      av_dict_set(&opts, "profile", "baseline", 0);
+      av_dict_set(&opts, "preset",  "veryfast", 0);
+      // Use main profile instead of the standard "baseline", we are aiming for better quality.
+      // Older devices (iPhone <4, Android <4) only supports baseline. Chromecast only supports >=4.1...
+      av_dict_set(&opts, "profile", "main", 0); // L3.0
       av_dict_set(&opts, "tune",    "zerolatency", 0);
 
-      if (t->t_props.tp_vbitrate == 0) {
+      // If we are encoding HD, upgrade the profile to high.
+      if (octx->height >= 720 && t->t_props.tp_resolution >=720) {
+        av_dict_set(&opts, "profile", "high", 0); // L3.1
+      }
+
+      // Default "auto" CRF settings. Aimed for quality without being too agressive.
+      if (t->t_props.tp_vbitrate == 0 ) {
         octx->qmin = 10;
         octx->qmax = 30;
-      } else {
+      }
+
+      // Stream profile vbitrate 1-63 is used for user specified qmin quantizer (CRF mode).
+      if (t->t_props.tp_vbitrate >0 && t->t_props.tp_vbitrate <64) {
+        octx->qmin = t->t_props.tp_vbitrate; // qmax = 51 in all default profiles, let's stick with it for now.
+      } else { // Bitrate limited encoding (CBR mode).
         octx->bit_rate       = t->t_props.tp_vbitrate * 1000;
-        octx->rc_max_rate    = octx->bit_rate * 1.05;
+        octx->rc_max_rate    = octx->bit_rate;
       }
 
       octx->rc_buffer_size = 8 * 1024 * 224;
@@ -1406,8 +1427,10 @@ transcoder_init_audio(transcoder_t *t, streaming_start_component_t *ssc)
 
   sct = codec_id2streaming_component_type(ocodec->id);
 
-  if (sct == ssc->ssc_type)
+  // Don't transcode to identical output codec unless the streaming profile specifies a bitrate limiter.
+  if (sct == ssc->ssc_type && t->t_props.tp_abitrate <16 ) {
     return transcoder_init_stream(t, ssc);
+  }
 
   as = calloc(1, sizeof(audio_stream_t));
 
@@ -1767,6 +1790,7 @@ transcoder_set_properties(streaming_target_t *st,
   tp->tp_channels   = props->tp_channels;
   tp->tp_bandwidth  = props->tp_bandwidth;
   tp->tp_vbitrate   = props->tp_vbitrate;
+  tp->tp_abitrate   = props->tp_abitrate;
   tp->tp_resolution = props->tp_resolution;
 
   memcpy(tp->tp_language, props->tp_language, 4);
index 81c04e8de55855fa3b0b126530f59ebe15b6c8af..53fb690e5eef6902ed92ff97ee26a9c480969074 100644 (file)
@@ -28,6 +28,7 @@ typedef struct transcoder_prop {
   int8_t   tp_channels;
   int32_t  tp_bandwidth;
   int32_t  tp_vbitrate;
+  int32_t  tp_abitrate;
   char     tp_language[4];
   int32_t  tp_resolution;
 
index eadd941da4ebacd078b8ec7e56e43d83a118d34c..1655b168f18e763d008e38e8b695f22baa725611 100644 (file)
@@ -1020,6 +1020,7 @@ typedef struct profile_transcode {
   uint32_t pro_channels;
   uint32_t pro_bandwidth;
   uint32_t pro_vbitrate;
+  uint32_t pro_abitrate;
   char    *pro_language;
   char    *pro_vcodec;
   char    *pro_acodec;
@@ -1230,6 +1231,13 @@ const idclass_t profile_transcode_class =
       .def.s    = "libvorbis",
       .list     = profile_class_acodec_list,
     },
+    {
+      .type     = PT_U32,
+      .id       = "abitrate",
+      .name     = "Audio Bitrate (kb/s) (0=Auto)",
+      .off      = offsetof(profile_transcode_t, pro_abitrate),
+      .def.u32  = 0,
+    },
     {
       .type     = PT_STR,
       .id       = "scodec",
@@ -1260,6 +1268,12 @@ profile_transcode_vbitrate(profile_transcode_t *pro)
   return pro->pro_vbitrate;
 }
 
+static int
+profile_transcode_abitrate(profile_transcode_t *pro)
+{
+  return pro->pro_abitrate;
+}
+
 static int
 profile_transcode_can_share(profile_chain_t *prch,
                             profile_chain_t *joiner)
@@ -1286,6 +1300,8 @@ profile_transcode_can_share(profile_chain_t *prch,
     return 0;
   if (profile_transcode_vbitrate(pro1) != profile_transcode_vbitrate(pro2))
     return 0;
+  if (profile_transcode_abitrate(pro1) != profile_transcode_abitrate(pro2))
+    return 0;
   if (strcmp(pro1->pro_language ?: "", pro2->pro_language ?: ""))
     return 0;
   return 1;
@@ -1314,6 +1330,7 @@ profile_transcode_work(profile_chain_t *prch,
   props.tp_channels   = pro->pro_channels;
   props.tp_bandwidth  = profile_transcode_bandwidth(pro);
   props.tp_vbitrate   = profile_transcode_vbitrate(pro);
+  props.tp_abitrate   = profile_transcode_abitrate(pro);
   strncpy(props.tp_language, pro->pro_language ?: "", 3);
 
   dst = prch->prch_gh = globalheaders_create(dst);