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;
 
