[FFmpeg-devel] patch 3. Adding support for the multiprog TS
ffmpeg at a.legko.ru
ffmpeg at a.legko.ru
Wed Jun 28 15:13:06 EEST 2017
subject: program inside TS MUST have it's own PCR pid. so, the new algo
solves the problem, selecting (auto mode) PCR pid inside the program.
first, video stream, if no video - audio, if no audio - any first stream
in the program. old behaviour remains for 1-prog TS. it is possible to set
pcr_pid via program options.
full example, using the new code (4 progs inside TS):
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
-------------- next part --------------
From d36f6f2a291c842654d3836e650b9f9fb2b16774 Mon Sep 17 00:00:00 2001
From: root <ffmpeg at scil.sinp.msu.ru>
Date: Wed, 28 Jun 2017 14:56:34 +0300
Subject: [PATCH 3/3] add multiprog mode PCR (automatic) selection algo, thus
making ffmpeg to produce multiprog TS. corrected behaviour with some metadata
(prog name, provider name).
---
libavformat/mpegtsenc.c | 162 ++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 136 insertions(+), 26 deletions(-)
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
More information about the ffmpeg-devel
mailing list