From patchwork Wed Jun 28 12:13:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ffmpeg@a.legko.ru X-Patchwork-Id: 4145 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.1.76 with SMTP id 73csp3225314vsb; Wed, 28 Jun 2017 05:13:20 -0700 (PDT) X-Received: by 10.28.167.207 with SMTP id q198mr7540152wme.36.1498652000201; Wed, 28 Jun 2017 05:13:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1498652000; cv=none; d=google.com; s=arc-20160816; b=HeLMsuG+0aZk7RpsGI4wMzj4SN3mqNLH1d4Uw5mjb5lOsqIzKNMbmElOHsNSiyWj0L f7h8Fet9mssDhRBu5+tu1IAfdUaEYL3rLxwMmRIcUOIBIowDWw/TC3bdtUkx24IZuC49 J4IMq68RIq0wYlDgQXyDGMejw17rDVCGEm+hnJPTejTM0YP5J/ixybXmC36E2MqoCNhk 54/X+giGApMiSpelmy5wqE/CLzLMbM1kbeAYiEaHi5FwGrRjRffjqWXYxVhueiUO1CgA AzZuGgrV1KmvIZ5yzNv63kKqPVcCF/vIxb/9GrjCn8DuO9OWpmfnQRwOsCXtCmceVuPe DIhQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:content-id :mime-version:user-agent:message-id:to:from:date:delivered-to :arc-authentication-results; bh=ILNlclTo7AMm71Mdec/mo8acdfisqzqQ7nH63Qpqh+c=; b=DuLSKS/fHN0Y5Q9hMHaNaFU9SPvbQpOAgkHQYsnAgFSspdzY4uVsU6eS2NNuBAdJCF ZOEs1XO/4h3/eOD2ryDf5kB17TWIzBJgetpZVerLkqj8OYlTTcFaEDivozhoJIcWAfCI uz6HgOfq42FZSx/TZCnqmzmj9uuL0iIqM7fyTpJrLLJ1gxQ5upAL2bxJgFVx9HJOeRZV fKDZU8f9Dncm5TO5dbC12nOLHEEE9dRX2vRUecaH7valwiBxJoHCZDBGfpemZ6P1F/Um iF2MW+OiaaO2mMmO9CeW5+9a6kx1X3LyRo0DRTdsOFHr8r10iUSy+/Pz1Q+oL/Exsi3c BVVQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 13si5493917wmm.132.2017.06.28.05.13.19; Wed, 28 Jun 2017 05:13:20 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B5ECF68A511; Wed, 28 Jun 2017 15:13:14 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from scil.sinp.msu.ru (scil.sinp.msu.ru [213.131.0.130]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id D9A4668A455 for ; Wed, 28 Jun 2017 15:13:08 +0300 (EEST) Received: from ffmpeg (helo=localhost) by scil.sinp.msu.ru with local-esmtp (Exim 4.86) (envelope-from ) id 1dQBqE-000768-Ft for ffmpeg-devel@ffmpeg.org; Wed, 28 Jun 2017 15:13:08 +0300 Date: Wed, 28 Jun 2017 15:13:06 +0300 (MSK) From: ffmpeg@a.legko.ru X-X-Sender: ffmpeg@scil.sinp.msu.ru To: ffmpeg-devel@ffmpeg.org Message-ID: User-Agent: Alpine 2.20 (LNX 67 2015-01-07) MIME-Version: 1.0 Content-ID: X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "scil.sinp.msu.ru", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see vvs for details. Content preview: 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. [...] Content analysis details: (0.0 points, 6.5 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different -0.0 NO_RELAYS Informational: message was not relayed via SMTP Subject: [FFmpeg-devel] patch 3. Adding support for the multiprog TS X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 From d36f6f2a291c842654d3836e650b9f9fb2b16774 Mon Sep 17 00:00:00 2001 From: root 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(-) -- 2.7.4 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;