Hi!
(corrected version of the patch.)

1. adding missed but required options for libavformat/mpegts encoder in
   ffmpeg_opt.c. also, it makes it possible to add pcr_pid for separate
   program inside TS.
   options are:
     service_provider: any provider name  (only default FFMPEG is present in 
original code)
     service_name: alias for title, used in mpegtsenc.c. it is present there, 
but never defined.
     pcr_pid: if required, it is possible to set the PCR pid for separate 
program inside TS

2. ffmpeg.c, when encoding multiple streams, stops encoding threads even
   when loop counter is set for separate input stream. adding corresponding
   function to correct the situation.

3. libavformat/mpegtsenc.c: adding multiprogram TS mode; thus, streams
   can be organized into progs as it is done in DVB streams. for that, PCR
   selection (auto) algo was changed (according to TS standart, each prog
   must have PCR pid inside). old PCR selection (auto) mode remains for 1-prog 
case.

4. possible to set default title|service_name/service_provider/pcr_pid
   via -metadata option (as in example below for the last prog). metadata
   options are used in 1-prog stream.


following example is for multi-prog TS streaming (open VLC with udp://@1234 and look at Playback/Program menu). here we have 4 progs with the loop(3 times) for auu.wav (when it stops, streaming remains with 1
silent prog):

ffmpeg -re \
        -i ZZ.avi \
        -i test.wav \
        -stream_loop 3 -i auu.wav \
        -i existone.mp3 \
        -map 0:v \
        -map 0:a \
        -map_channel 0.1.0:1.0 \
        -map_channel 0.1.1:1.1 \
        -vcodec libx264 -b:v 400k \
        -mpegts_original_network_id 0x1122 \
        -mpegts_transport_stream_id 0x3344 \
        -mpegts_service_id 0x5566 \
        -streamid 0:0x159 \
        -metadata service_provider="Some provider" \
        -metadata service_name="Some Channel" \
        -c:a:0 libfdk_aac -profile:a aac_he  -ac 2 -b:a 32k \
        -streamid 1:0x160 \
        -f mpegts \
        -map 1:a \
        -mpegts_original_network_id 0x1123 \
        -mpegts_transport_stream_id 0x3345 \
        -mpegts_service_id 0x55CA \
        -map_channel 1.0.0:2.0 \
        -map_channel 1.0.1:2.1 \
        -c:a:1 libfdk_aac -profile:a aac_he_v2  -ac 2 -b:a 32k \
        -streamid 2:0x180 \
        -f mpegts \
        -map 2:a \
        -mpegts_original_network_id 0x1127 \
        -mpegts_transport_stream_id 0x3348 \
        -mpegts_service_id 0x55CE \
        -map_channel 2.0.0:3.0 \
        -map_channel 2.0.1:3.1 \
        -c:a:2 libfdk_aac -profile:a aac_he_v2  -ac 2 -b:a 32k \
        -streamid 3:0x182 \
        -map 3:a \
        -mpegts_original_network_id 0x1129 \
        -mpegts_transport_stream_id 0x3349 \
        -mpegts_service_id 0x55CF \
        -map_channel 3.0.0:4.0 \
        -map_channel 3.0.1:4.1 \
        -c:a:3 libfdk_aac -profile:a aac_he_v2  -ac 2 -b:a 32k \
        -streamid 4:0x184 \
        -program 
title="Xren0":service_name="Zanunda":service_provider="provider4":program_num=0x5576:st=0:st=1
 \
        -program 
title="Xren1":service_provider="provider4":program_num=0x5578:st=2 \
        -program 
title="Xren2":service_provider="provider5":program_num=0x5579:st=3 \
        -program program_num=0x5581:st=4 \
        -f mpegts  udp://192.11.1.12:1234\&pkt_size=1316
From b043d9f5c894f4b9c9964e43392ee42adce2ef33 Mon Sep 17 00:00:00 2001
From: root <ffm...@scil.sinp.msu.ru>
Date: Fri, 23 Jun 2017 17:01:07 +0300
Subject: [PATCH] ffmpeg.c - add thread restart (when required by looping) for
 multi-stream encoding ffmpeg_opt.c - add required but missing options for
 mpegtsenc.c mpegtsenc.c - add support for multi-programm mpeg TS, add PCR
 selection algo for it

---
 ffmpeg.c                |  27 ++++++++
 ffmpeg_opt.c            |   7 ++-
 libavformat/mpegtsenc.c | 162 ++++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 169 insertions(+), 27 deletions(-)

diff --git a/ffmpeg.c b/ffmpeg.c
index a783e6e..2866754 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -4013,6 +4013,29 @@ static void free_input_threads(void)
     }
 }
 
+static int init_input_thread(int i)
+{
+    int ret;
+  
+    if (nb_input_files == 1)
+       return 0;
+
+    InputFile *f = input_files[i];
+    if (f->ctx->pb ? !f->ctx->pb->seekable :
+       strcmp(f->ctx->iformat->name, "lavfi"))
+           f->non_blocking = 1;
+    ret = av_thread_message_queue_alloc(&f->in_thread_queue,
+           f->thread_queue_size, sizeof(AVPacket));
+    if (ret < 0)
+       return ret;
+    if ((ret = pthread_create(&f->thread, NULL, input_thread, f))) {
+       av_log(NULL, AV_LOG_ERROR, "pthread_create failed: %s. Try to increase 
`ulimit -v` or decrease `ulimit -s`.\n", strerror(ret));
+       av_thread_message_queue_free(&f->in_thread_queue);
+       return AVERROR(ret);
+    }
+return 0;
+}
+ 
 static int init_input_threads(void)
 {
     int i, ret;
@@ -4191,9 +4214,13 @@ static int process_input(int file_index)
         ifile->eagain = 1;
         return ret;
     }
+
     if (ret < 0 && ifile->loop) {
         if ((ret = seek_to_start(ifile, is)) < 0)
             return ret;
+#if HAVE_PTHREADS
+        init_input_thread(file_index);
+#endif
         ret = get_input_packet(ifile, &pkt);
         if (ret == AVERROR(EAGAIN)) {
             ifile->eagain = 1;
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index bb6001f..aa4ffb5 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -2653,13 +2653,18 @@ loop_end:
             if (!*p2)
                 exit_program(1);
             p2++;
-
             if (!strcmp(key, "title")) {
                 av_dict_set(&program->metadata, "title", p2, 0);
             } else if (!strcmp(key, "program_num")) {
             } else if (!strcmp(key, "st")) {
                 int st_num = strtol(p2, NULL, 0);
                 av_program_add_stream_index(oc, progid, st_num);
+            } else if (!strcmp(key, "service_provider")) {
+                av_dict_set(&program->metadata, "service_provider", p2, 0);
+            } else if (!strcmp(key, "service_name")) {
+                av_dict_set(&program->metadata, "service_name", p2, 0);
+            } else if (!strcmp(key, "pcr_pid")) {
+                av_dict_set(&program->metadata, "pcr_pid", p2, 0);
             } else {
                 av_log(NULL, AV_LOG_FATAL, "Unknown program key %s.\n", key);
                 exit_program(1);
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index acea2e9..15260a9 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -59,6 +59,7 @@ typedef struct MpegTSService {
     int pcr_pid;
     int pcr_packet_count;
     int pcr_packet_period;
+    int pcr_type;      /* if the service has a/v pid: 
AVMEDIA_TYPE_UNKNOWN/AUDIO/VIDEO...*/
     AVProgram *program;
 } MpegTSService;
 
@@ -707,7 +708,8 @@ static void mpegts_write_sdt(AVFormatContext *s)
 
 static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid,
                                          const char *provider_name,
-                                         const char *name)
+                                         const char *name,
+                                         int pcr_pid)
 {
     MpegTSService *service;
 
@@ -716,7 +718,7 @@ static MpegTSService *mpegts_add_service(MpegTSWrite *ts, 
int sid,
         return NULL;
     service->pmt.pid       = ts->pmt_start_pid + ts->nb_services;
     service->sid           = sid;
-    service->pcr_pid       = 0x1fff;
+    service->pcr_pid       = pcr_pid; /* was 0x1fff */
     service->provider_name = av_strdup(provider_name);
     service->name          = av_strdup(name);
     if (!service->provider_name || !service->name)
@@ -763,11 +765,12 @@ static int mpegts_init(AVFormatContext *s)
     MpegTSWriteStream *ts_st;
     MpegTSService *service;
     AVStream *st, *pcr_st = NULL;
-    AVDictionaryEntry *title, *provider;
+    AVDictionaryEntry *title, *provider, *p_pid;
+    char *endz;
     int i, j;
-    const char *service_name;
-    const char *provider_name;
-    int *pids;
+    const char *service_name, *dflt_service_name;
+    const char *provider_name, *dflt_provider_name;
+    int *pids, pcr_pid = 0x1fff, dflt_pcr_pid = 0x1fff;
     int ret;
 
     if (s->max_delay < 0) /* Not set by the caller */
@@ -778,17 +781,34 @@ static int mpegts_init(AVFormatContext *s)
 
     ts->tsid = ts->transport_stream_id;
     ts->onid = ts->original_network_id;
+
+    dflt_service_name = DEFAULT_SERVICE_NAME;
+    title = av_dict_get(s->metadata, "title", NULL, 0);
+    if(title != NULL)
+          dflt_service_name = title->value;
+    else {
+      title = av_dict_get(s->metadata, "service_name", NULL, 0);
+      if(title != NULL)
+        dflt_service_name = title->value;
+      }
+
+    dflt_provider_name = DEFAULT_PROVIDER_NAME;
+    provider = av_dict_get(s->metadata, "service_provider", NULL, 0);
+    if(provider != NULL)
+      dflt_provider_name = provider->value;
+
+    p_pid  = av_dict_get(s->metadata, "pcr_pid", NULL, 0);
+    if (p_pid)  {
+      endz = NULL;
+      dflt_pcr_pid = strtol(p_pid->value, &endz, 0);
+      }
+
     if (!s->nb_programs) {
-        /* allocate a single DVB service */
-        title = av_dict_get(s->metadata, "service_name", NULL, 0);
-        if (!title)
-            title = av_dict_get(s->metadata, "title", NULL, 0);
-        service_name  = title ? title->value : DEFAULT_SERVICE_NAME;
-        provider      = av_dict_get(s->metadata, "service_provider", NULL, 0);
-        provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
+        /* allocate a single DVB service/no prog */
+        service_name  = dflt_service_name;
+        provider_name = dflt_provider_name;
         service       = mpegts_add_service(ts, ts->service_id,
-                                           provider_name, service_name);
-
+                                      provider_name, service_name, 
dflt_pcr_pid);
         if (!service)
             return AVERROR(ENOMEM);
 
@@ -802,11 +822,18 @@ static int mpegts_init(AVFormatContext *s)
             title = av_dict_get(program->metadata, "service_name", NULL, 0);
             if (!title)
                 title = av_dict_get(program->metadata, "title", NULL, 0);
-            service_name  = title ? title->value : DEFAULT_SERVICE_NAME;
+            service_name  = title ? title->value : dflt_service_name;
             provider      = av_dict_get(program->metadata, "service_provider", 
NULL, 0);
-            provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
+            provider_name = provider ? provider->value : dflt_provider_name;
+            p_pid         = av_dict_get(s->metadata, "pcr_pid", NULL, 0);
+            if (p_pid) {
+                endz = NULL;
+                pcr_pid = strtol(p_pid->value, &endz, 0);
+                }
+                else
+                pcr_pid = dflt_pcr_pid;
             service       = mpegts_add_service(ts, program->id,
-                                               provider_name, service_name);
+                                               provider_name, service_name, 
pcr_pid);
 
             if (!service)
                 return AVERROR(ENOMEM);
@@ -901,12 +928,7 @@ static int mpegts_init(AVFormatContext *s)
         ts_st->first_pts_check = 1;
         ts_st->cc              = 15;
         ts_st->discontinuity   = ts->flags & MPEGTS_FLAG_DISCONT;
-        /* update PCR pid by using the first video stream */
-        if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
-            service->pcr_pid == 0x1fff) {
-            service->pcr_pid = ts_st->pid;
-            pcr_st           = st;
-        }
+
         if (st->codecpar->codec_id == AV_CODEC_ID_AAC &&
             st->codecpar->extradata_size > 0) {
             AVStream *ast;
@@ -940,8 +962,94 @@ static int mpegts_init(AVFormatContext *s)
     }
 
     av_freep(&pids);
+    
+    /* automatic PCR pid selection in multiprog mode */
+    if(s->nb_programs > 0) {
+    MpegTSService *serv;
+    int k;
+    /* find a/v pid for PCR or any pid if no a/v found */
+    for (j = 0; j < ts->nb_services; j++) {
+        serv = ts->services[j];
+        serv->pcr_type = AVMEDIA_TYPE_UNKNOWN;
+        AVProgram *prog = serv->program;
+        if (serv->pcr_pid == 0x1fff) {
+           for (k = 0; k < prog->nb_stream_indexes; k++) {
+               st = s->streams[prog->stream_index[k]];
+               if(serv->pcr_type == AVMEDIA_TYPE_UNKNOWN &&
+                  (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
+                   st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO))
+                         serv->pcr_type = st->codecpar->codec_type;
+               else /* video stream preference */
+                  if(serv->pcr_type == AVMEDIA_TYPE_AUDIO &&
+                     st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
+                         serv->pcr_type = st->codecpar->codec_type;
+            }
+        }
+    }
+
+    for (j = 0; j < ts->nb_services; j++) {
+        serv = ts->services[j];
+        AVProgram *prog = serv->program;
+        if(serv->pcr_pid == 0x1fff) {
+          /* find first a/v media PID to hold PCR; calculate PCR period */
+          for (k = 0; k < prog->nb_stream_indexes; k++) {
+              st = s->streams[prog->stream_index[k]];
+              if(serv->pcr_type == AVMEDIA_TYPE_UNKNOWN ||
+                 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+                  serv->pcr_type == AVMEDIA_TYPE_VIDEO) ||
+                 (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
+                  serv->pcr_type == AVMEDIA_TYPE_AUDIO)) {
+                         serv->pcr_pid = st->id;
+              if (ts->mux_rate > 1) {
+                         serv->pcr_packet_period = (int64_t)ts->mux_rate * \
+                                                  ts->pcr_period /
+                                                  (TS_PACKET_SIZE * 8 * 1000);
+                         } else {
+                         if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+                             int frame_size =
+                                av_get_audio_frame_duration2(st->codecpar, 0);
+                              if (!frame_size) {
+                                  av_log(s, AV_LOG_WARNING,
+                                    "pcr_packet_period: frame size not set\n");
+                                  serv->pcr_packet_period =
+                                    st->codecpar->sample_rate / (10 * 512);
+                                  } else
+                                  serv->pcr_packet_period =
+                                  st->codecpar->sample_rate / (10 * 
frame_size);
+                         } else {
+                        /* max delta PCR 0.1s */
+                        /* TODO: should be avg_frame_rate */
+                            ts_st = st->priv_data;
+                            serv->pcr_packet_period =
+                                 ts_st->user_tb.den / (10 * 
ts_st->user_tb.num);
+                        }
+              }
+              break;
+              }
+          } /* for k */
+        }
+        if (!serv->pcr_packet_period)
+            serv->pcr_packet_period = 1;
+        /* send PCR as soon as possible */
+        serv->pcr_packet_count = serv->pcr_packet_period;
+        }
 
-    /* if no video stream, use the first stream as PCR */
+    if (ts->mux_rate > 1) {
+        ts->sdt_packet_period      = (int64_t)ts->mux_rate * SDT_RETRANS_TIME /
+                                     (TS_PACKET_SIZE * 8 * 1000);
+        ts->pat_packet_period      = (int64_t)ts->mux_rate * PAT_RETRANS_TIME /
+                                     (TS_PACKET_SIZE * 8 * 1000);
+
+        if (ts->copyts < 1)
+            ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, 
AV_TIME_BASE);
+    } else {
+        /* Arbitrary values, PAT/PMT will also be written on video key frames 
*/
+        ts->sdt_packet_period = 200;
+        ts->pat_packet_period = 40;
+    }
+
+    }  else { /* default PCR pid selection in singleprog mode */
+        /* if no video stream, use the first stream as PCR */
     if (service->pcr_pid == 0x1fff && s->nb_streams > 0) {
         pcr_st           = s->streams[0];
         ts_st            = pcr_st->priv_data;
@@ -983,6 +1091,8 @@ static int mpegts_init(AVFormatContext *s)
             service->pcr_packet_period = 1;
     }
 
+    }
+
     ts->last_pat_ts = AV_NOPTS_VALUE;
     ts->last_sdt_ts = AV_NOPTS_VALUE;
     // The user specified a period, use only it
@@ -994,7 +1104,7 @@ static int mpegts_init(AVFormatContext *s)
     }
 
     // output a PCR as soon as possible
-    service->pcr_packet_count = service->pcr_packet_period;
+    // service->pcr_packet_count = service->pcr_packet_period;
     ts->pat_packet_count      = ts->pat_packet_period - 1;
     ts->sdt_packet_count      = ts->sdt_packet_period - 1;
 
-- 
2.7.4

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to