From patchwork Wed Mar 29 12:12:02 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: 3168 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.44.195 with SMTP id s186csp1061939vss; Wed, 29 Mar 2017 05:12:15 -0700 (PDT) X-Received: by 10.223.163.80 with SMTP id d16mr201336wrb.36.1490789534919; Wed, 29 Mar 2017 05:12:14 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id s10si6959685wmf.42.2017.03.29.05.12.14; Wed, 29 Mar 2017 05:12:14 -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 705BF689A40; Wed, 29 Mar 2017 15:11:49 +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 EB83C68825C for ; Wed, 29 Mar 2017 15:11:42 +0300 (EEST) Received: from ffmpeg (helo=localhost) by scil.sinp.msu.ru with local-esmtp (Exim 4.86) (envelope-from ) id 1ctCSI-0007WQ-KL for ffmpeg-devel@ffmpeg.org; Wed, 29 Mar 2017 15:12:04 +0300 Date: Wed, 29 Mar 2017 15:12:02 +0300 (MSK) From: ffmpeg@a.legko.ru X-X-Sender: ffmpeg@scil.sinp.msu.ru To: FFmpeg development discussions and patches In-Reply-To: <20170328201352.GX4714@nb4> Message-ID: References: <20170328201352.GX4714@nb4> User-Agent: Alpine 2.20 (LNX 67 2015-01-07) MIME-Version: 1.0 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: Hi! Thanx for help with git! Reposting the same patch in git format now. From 248d67b353cd76f201b7174a6bdf160e6c6f64b1 Mon Sep 17 00:00:00 2001 From: Vadka aka VVS Date: Wed, 29 Mar 2017 15:09:32 +0300 Subject: [PATCH] ffmpeg.c - bug with streams loop/repeat fixed; ffmpeg_opt.c - adding missed options for libavformat/mpegtsenc.c; libavformat/mpegtsenc.c - PCR pids selection procedure changed, making it possible to broadcast standard mpeg TS/DVB streams with multiple programs (it is possible to define pcr_pid manually now). [...] 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: Re: [FFmpeg-devel] mpeg TS encoder PCR algo + looping 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" Hi! Thanx for help with git! Reposting the same patch in git format now. From 248d67b353cd76f201b7174a6bdf160e6c6f64b1 Mon Sep 17 00:00:00 2001 From: Vadka aka VVS Date: Wed, 29 Mar 2017 15:09:32 +0300 Subject: [PATCH] ffmpeg.c - bug with streams loop/repeat fixed; ffmpeg_opt.c - adding missed options for libavformat/mpegtsenc.c; libavformat/mpegtsenc.c - PCR pids selection procedure changed, making it possible to broadcast standard mpeg TS/DVB streams with multiple programs (it is possible to define pcr_pid manually now). --- ffmpeg.c | 26 ++++++++++ ffmpeg_opt.c | 7 ++- libavformat/mpegtsenc.c | 131 ++++++++++++++++++++++++++++++++---------------- 3 files changed, 120 insertions(+), 44 deletions(-) -- 2.9.0 diff --git a/ffmpeg.c b/ffmpeg.c index 3aa1e78..254960f 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -4028,6 +4028,31 @@ static int init_input_threads(void) return 0; } +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 get_input_packet_mt(InputFile *f, AVPacket *pkt) { return av_thread_message_queue_recv(f->in_thread_queue, pkt, @@ -4182,6 +4207,7 @@ static int process_input(int file_index) if (ret < 0 && ifile->loop) { if ((ret = seek_to_start(ifile, is)) < 0) return ret; + init_input_thread(file_index); ret = get_input_packet(ifile, &pkt); if (ret == AVERROR(EAGAIN)) { ifile->eagain = 1; diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c index ffe1abd..a5eb821 100644 --- a/ffmpeg_opt.c +++ b/ffmpeg_opt.c @@ -2609,7 +2609,12 @@ loop_end: } else if (!strcmp(key, "st")) { int st_num = strtol(p2, NULL, 0); av_program_add_stream_index(oc, progid, st_num); - } else { + } 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 { 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 3250dde..e9f0ab8 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,7 @@ 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 +717,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 +764,11 @@ static int mpegts_init(AVFormatContext *s) MpegTSWriteStream *ts_st; MpegTSService *service; AVStream *st, *pcr_st = NULL; - AVDictionaryEntry *title, *provider; + AVDictionaryEntry *title, *provider, *p_pid; int i, j; const char *service_name; const char *provider_name; - int *pids; + int *pids, pcr_pid = 0x1fff; int ret; if (s->max_delay < 0) /* Not set by the caller */ @@ -786,8 +787,11 @@ static int mpegts_init(AVFormatContext *s) 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; + p_pid = av_dict_get(s->metadata, "pcr_pid", NULL, 0); + if(p_pid) + pcr_pid = atoi(p_pid->value); service = mpegts_add_service(ts, ts->service_id, - provider_name, service_name); + provider_name, service_name, pcr_pid); if (!service) return AVERROR(ENOMEM); @@ -805,8 +809,13 @@ static int mpegts_init(AVFormatContext *s) service_name = title ? title->value : DEFAULT_SERVICE_NAME; provider = av_dict_get(program->metadata, "service_provider", NULL, 0); provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME; + p_pid = av_dict_get(s->metadata, "pcr_pid", NULL, 0); + if(p_pid) + pcr_pid = atoi(p_pid->value); + else + pcr_pid = 0x1fff; service = mpegts_add_service(ts, program->id, - provider_name, service_name); + provider_name, service_name, pcr_pid); if (!service) return AVERROR(ENOMEM); @@ -901,12 +910,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; @@ -941,17 +945,76 @@ static int mpegts_init(AVFormatContext *s) av_freep(&pids); - /* 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; - service->pcr_pid = ts_st->pid; - } else - ts_st = pcr_st->priv_data; + 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; + } + } + } + if (!serv->pcr_packet_period) + serv->pcr_packet_period = 1; + av_log(s, AV_LOG_VERBOSE, + "service 0x%x: pcr every %d pkts\n", serv->sid, serv->pcr_packet_period); + /* send PCR as soon as possible */ + serv->pcr_packet_count = serv->pcr_packet_period; + } + + if (ts->mux_rate > 1) { - service->pcr_packet_period = (int64_t)ts->mux_rate * ts->pcr_period / - (TS_PACKET_SIZE * 8 * 1000); 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 / @@ -963,24 +1026,6 @@ static int mpegts_init(AVFormatContext *s) /* Arbitrary values, PAT/PMT will also be written on video key frames */ ts->sdt_packet_period = 200; ts->pat_packet_period = 40; - if (pcr_st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - int frame_size = av_get_audio_frame_duration2(pcr_st->codecpar, 0); - if (!frame_size) { - av_log(s, AV_LOG_WARNING, "frame size not set\n"); - service->pcr_packet_period = - pcr_st->codecpar->sample_rate / (10 * 512); - } else { - service->pcr_packet_period = - pcr_st->codecpar->sample_rate / (10 * frame_size); - } - } else { - // max delta PCR 0.1s - // TODO: should be avg_frame_rate - service->pcr_packet_period = - ts_st->user_tb.den / (10 * ts_st->user_tb.num); - } - if (!service->pcr_packet_period) - service->pcr_packet_period = 1; } ts->last_pat_ts = AV_NOPTS_VALUE; @@ -994,7 +1039,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; @@ -1003,9 +1048,9 @@ static int mpegts_init(AVFormatContext *s) else av_log(s, AV_LOG_VERBOSE, "muxrate %d, ", ts->mux_rate); av_log(s, AV_LOG_VERBOSE, - "pcr every %d pkts, sdt every %d, pat/pmt every %d pkts\n", - service->pcr_packet_period, - ts->sdt_packet_period, ts->pat_packet_period); + "sdt every %d, pat/pmt every %d pkts\n", + service->pcr_packet_period, + ts->sdt_packet_period, ts->pat_packet_period); if (ts->m2ts_mode == -1) { if (av_match_ext(s->filename, "m2ts")) {