From patchwork Thu Aug 22 14:26:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Delannoy X-Patchwork-Id: 14655 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id C3CB144A029 for ; Thu, 22 Aug 2019 17:27:04 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A194D68AB65; Thu, 22 Aug 2019 17:27:04 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-yb1-f173.google.com (mail-yb1-f173.google.com [209.85.219.173]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8C8C968AB57 for ; Thu, 22 Aug 2019 17:26:57 +0300 (EEST) Received: by mail-yb1-f173.google.com with SMTP id c9so2601258ybf.2 for ; Thu, 22 Aug 2019 07:26:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=tB2EHTYkacdS2V3fQtd86b8x7S5+tYkmHQao1ApP4dU=; b=b9sMpQZMj1TlkcyXhbwLJemIhbGJnswUKWTs5Husg343cu9BWoYQSklS602HvZ9qb/ rMWmlux0FDkp7NmsrQ7F0v2uTH9b1SaV86elyuY+fsHIsgaeCP3+IOzRgY95rWVBoWYE MOGstbamyS4M9Gd8WsF9SEay9i6A05BKBJJs6Qm8T3U/URpuLCoQPIpkUdKDrXwb9/vR JwgiQdJ4lGUeQua0C9H2EqQXUy5+5x5IEQ6XttuFVOD6YozeqIEzufiio/GGru1rk4xG l0O0MlmsphwPyjmND1XyGfd+LJsOku+bVfBTNLYN55BLfWpm//5LlJ77TWK6ZrMRhgU5 Robg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=tB2EHTYkacdS2V3fQtd86b8x7S5+tYkmHQao1ApP4dU=; b=TxDckeImYBDicj+AlgZoxWUms1HOoxiRgzWR9h/s7Zv/JcTFfi0pbk0cjBOhQOVLLi 8Soml5bi6o5i9UvIzFJyjbL5nbj2W2Vt1nRbuwOetBKLLjtdmbN5fMnw1onqrvnyhfud taqoWHn9sQyiMxOFY0u3W3ZEGtuBHjK438j4fmmnpMslSVWFyFDjvr4NE3DmOsrUELE4 bz7IOh8eAtNn1aag6Cymd+5l3U4+L/mys7ccexrtgkrfHKoFZJ1gTeRzCRbICqhXp8ZL co7psinjrcszIPH8JVQalJyRepeud0y5aHvDsOqPRyo2tzhbBKUl6alPC1+HFxHeeOzC VNLA== X-Gm-Message-State: APjAAAXmyyobQJqB+fHfDVim9b4Yerqt9uSbSRPn5TKGaE1g+9VTWgHw e/eMl+SMDd1Fkj1lWnFoJn64CqX9OW9zB9x7O0kvrY7k X-Google-Smtp-Source: APXvYqx6noS24ODgWI97Ub5GPyEtNDT55vKx3Tl85uKHk6LbbrPICe9/supVIC2j+hMx3/1o1YVnwRT/cPz3Fc/ch9s= X-Received: by 2002:a25:aca:: with SMTP id 193mr26657127ybk.521.1566484015659; Thu, 22 Aug 2019 07:26:55 -0700 (PDT) MIME-Version: 1.0 References: <20190822104225.GI3219@michaelspb> In-Reply-To: From: Anthony Delannoy Date: Thu, 22 Aug 2019 16:26:44 +0200 Message-ID: To: FFmpeg development discussions and patches Subject: Re: [FFmpeg-devel] [PATCH] DVB EPG decoder 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 > > fails to build on MIPS > > Seems to be because of these two structs within EPGTable and EPGSubTable: > + struct { > + int nb_descriptors; > + void **descriptors; > + }; I made modifications to avoid issues you encountered and put fate modifications in the right commit(s). > Afaict, some patches change files that were added in earlier patches. This may > not be ideal. I committed changements to files (dvb.{h,c}) I added earlier because I need descriptors files (dvbdescriptors.{h,c}) before those changes and descriptors files need the first version of the dvb file (basic get functions). > Why are the big api changes necessary at all? I made those big changements to ease the implementation of all others DVB tables (i'd like to add support for NIT, AIT, TDT,... after EPG) by using the same helper functions (avpriv_dvb_get{8,16,32}()) and especially the same DVB descriptors code because each descriptor is supported by multiple table in general. Anthony Delannoy From 1cfd16650bb91ce25c03a289cf6723b02587a892 Mon Sep 17 00:00:00 2001 From: Anthony Delannoy Date: Wed, 21 Aug 2019 16:07:59 +0200 Subject: [PATCH 10/10] lavc/epgdec: add EPG data decoder New EPG table decoder which store an EPGTable in AVFrame::side_data as a AV_FRAME_DATA_EPG_TABLE type for each AVPacket decoded. --- Changelog | 1 + configure | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/epgdec.c | 278 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 282 insertions(+) create mode 100644 libavcodec/epgdec.c diff --git a/Changelog b/Changelog index 52096eed0e..7a369330fe 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,7 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. version : +- EPG data decoder - v360 filter - Intel QSV-accelerated MJPEG decoding - Intel QSV-accelerated VP9 decoding diff --git a/configure b/configure index 13d9726606..4dad16d73c 100755 --- a/configure +++ b/configure @@ -2687,6 +2687,7 @@ eac3_encoder_select="ac3_encoder" eamad_decoder_select="aandcttables blockdsp bswapdsp idctdsp mpegvideo" eatgq_decoder_select="aandcttables" eatqi_decoder_select="aandcttables blockdsp bswapdsp idctdsp" +epg_decoder_select="dvb" exr_decoder_deps="zlib" ffv1_decoder_select="rangecoder" ffv1_encoder_select="rangecoder" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index e49188357b..b9c42bdb14 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -300,6 +300,7 @@ OBJS-$(CONFIG_EATQI_DECODER) += eatqi.o eaidct.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_EIGHTBPS_DECODER) += 8bps.o OBJS-$(CONFIG_EIGHTSVX_EXP_DECODER) += 8svx.o OBJS-$(CONFIG_EIGHTSVX_FIB_DECODER) += 8svx.o +OBJS-$(CONFIG_EPG_DECODER) += epgdec.o OBJS-$(CONFIG_ESCAPE124_DECODER) += escape124.o OBJS-$(CONFIG_ESCAPE130_DECODER) += escape130.o OBJS-$(CONFIG_EVRC_DECODER) += evrcdec.o acelp_vectors.o lsp.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 22985325e0..b669c80bca 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -419,6 +419,7 @@ extern AVCodec ff_dss_sp_decoder; extern AVCodec ff_dst_decoder; extern AVCodec ff_eac3_encoder; extern AVCodec ff_eac3_decoder; +extern AVCodec ff_epg_decoder; extern AVCodec ff_evrc_decoder; extern AVCodec ff_ffwavesynth_decoder; extern AVCodec ff_flac_encoder; diff --git a/libavcodec/epgdec.c b/libavcodec/epgdec.c new file mode 100644 index 0000000000..2003bb1905 --- /dev/null +++ b/libavcodec/epgdec.c @@ -0,0 +1,278 @@ +/* + * epg data decoder + * Copyright (c) 2019 Anthony Delannoy + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file epg data decoder + */ + +#include "avcodec.h" +#include "internal.h" +#include "decode.h" +#include "libavutil/common.h" +#include "libavutil/dvb.h" +#include "libavutil/dvbdescriptors.h" +#include "libavformat/mpegts.h" + +typedef struct EpgTidInfo { + int last_version; + int last_section_num; + int last_segment_section_num; +} EpgTidInfo; + +typedef struct EPGContext { + const AVClass *class; + struct EpgTidInfo infos[4]; + int last_sched_table_id; + int o_last_sched_table_id; + AVPacket *pkt; +} EPGContext; + +static int epg_handle_descriptor(DvbDescriptorHeader *h, DvbDescriptor *desc, + EPGSubTable *subtable, const uint8_t **pp, + const uint8_t *p_end) +{ + void *data = desc->parse(desc, pp, p_end); + if (!data) + return AVERROR_INVALIDDATA; + memcpy(data, h, sizeof(DvbDescriptorHeader)); + + if (av_reallocp_array(&subtable->descriptors, (subtable->nb_descriptors + 1), sizeof(void*)) < 0) { + desc->free(data); + return AVERROR(ENOMEM); + } + subtable->descriptors[subtable->nb_descriptors++] = data; + + return 0; +} + +static int epg_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + EPGContext *epg_ctx = avctx->priv_data; + EpgTidInfo *epg_info; + DvbSectionHeader h1, *h = &h1; + const uint8_t *p, *p_end; + int val, ret, max_last_table_id; + uint8_t next_version; + AVFrameSideData *sd; + AVBufferRef *buf_ref; + EPGTable *table; + + if (!epg_ctx->pkt->data) { + ret = ff_decode_get_packet(avctx, epg_ctx->pkt); + if (ret < 0) + return ret; + } + + p = epg_ctx->pkt->data; + p_end = p + epg_ctx->pkt->size - 4; + + if (avpriv_dvb_parse_section_header(h, &p, p_end) < 0) + goto fail; + + table = av_epg_table_alloc(); + if (!table) + goto fail; + table->h = h1; + + val = avpriv_dvb_get16(&p, p_end); + if (val < 0) + goto fail; + table->ts_id = val; + + val = avpriv_dvb_get16(&p, p_end); + if (val < 0) + goto fail; + table->network_id = val; + + val = avpriv_dvb_get8(&p, p_end); + if (val < 0) + goto fail; + table->segment_last_section_num = val; + + val = avpriv_dvb_get8(&p, p_end); + if (val < 0) + goto fail; + table->last_tid = val; + + // Check eit data + switch (h->tid) { + case EIT_TID: + epg_info = &epg_ctx->infos[0]; + if (table->last_tid != EIT_TID || h->last_sec_num != table->segment_last_section_num) + goto fail; + break; + case OEIT_TID: + epg_info = &epg_ctx->infos[1]; + if (table->last_tid != OEIT_TID || h->last_sec_num != table->segment_last_section_num) + goto fail; + break; + case EITS_START_TID ... EITS_END_TID: + epg_info = &epg_ctx->infos[2]; + if (table->segment_last_section_num != h->sec_num) + goto fail; + max_last_table_id = FFMAX(table->last_tid, epg_ctx->last_sched_table_id); + if (table->last_tid != max_last_table_id) + goto fail; + epg_ctx->last_sched_table_id = max_last_table_id; + break; + case OEITS_START_TID ... OEITS_END_TID: + epg_info = &epg_ctx->infos[3]; + if (table->segment_last_section_num != h->sec_num) + goto fail; + max_last_table_id = FFMAX(table->last_tid, epg_ctx->o_last_sched_table_id); + if (table->last_tid != max_last_table_id) + goto fail; + epg_ctx->o_last_sched_table_id = max_last_table_id; + break; + default: + goto fail; + } + + next_version = (epg_info->last_version == 31) ? 0 : epg_info->last_version + 1; + if (epg_info->last_version != (-1) && + (h->version == epg_info->last_version || h->version == next_version)) + goto fail; + + // Subtables + while (p < p_end) { + const uint8_t *desc_list_end; + EPGSubTable *subtable; + + if (av_reallocp_array(&table->subtables, (table->nb_subtables + 1), sizeof(EPGSubTable*)) < 0) + goto fail; + + table->subtables[table->nb_subtables] = av_epg_subtable_alloc(); + if (!table->subtables[table->nb_subtables]) + goto fail; + subtable = table->subtables[table->nb_subtables++]; + + // Get event_id + val = avpriv_dvb_get16(&p, p_end); + if (val < 0) + break; + subtable->event_id = val; + + memcpy(subtable->start_time, p, 5); + p += 5; + + memcpy(subtable->duration, p, 3); + p += 3; + + val = avpriv_dvb_get16(&p, p_end); + if (val < 0) + break; + subtable->running_status = (val >> 13); + subtable->free_ca_mode = (val >> 12) & 0x1; + subtable->desc_loop_len = val & 0xfff; + + desc_list_end = p + subtable->desc_loop_len; + + // Descriptors + for (;;) { + DvbDescriptor *desc; + DvbDescriptorHeader h; + const uint8_t *desc_end; + + if (av_dvb_parse_descriptor_header(&h, &p, p_end) < 0) + break; + + if (!(desc = (DvbDescriptor*)av_dvb_get_descriptor(&h))) { + p += h.len; + continue; + } + + desc_end = p + h.len; + if (desc_end > desc_list_end) + break; + + if (epg_handle_descriptor(&h, desc, subtable, &p, desc_end) < 0) + break; + + p = desc_end; + } + p = desc_list_end; + } + + // CRC32 + val = avpriv_dvb_get32(&p_end, (p_end + 4)); + if (val < 0) + goto fail; + table->crc = val; + + buf_ref = av_buffer_allocz(sizeof(*table) + AV_INPUT_BUFFER_PADDING_SIZE); + if (!buf_ref) + goto fail; + buf_ref->data = (uint8_t*)table; + frame->buf[0] = buf_ref; + + sd = av_frame_new_side_data(frame, AV_FRAME_DATA_EPG_TABLE, sizeof(*table)); + sd->data = (uint8_t*)table; + + frame->pts = epg_ctx->pkt->pts; + frame->pkt_dts = epg_ctx->pkt->dts; + frame->pkt_size = epg_ctx->pkt->size; + + av_packet_unref(epg_ctx->pkt); + return 0; + +fail: + av_packet_unref(epg_ctx->pkt); + av_epg_table_free(&table); + return AVERROR_INVALIDDATA; +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + EPGContext *epg_ctx = avctx->priv_data; + + for (int i = 0; i < 4; i++) + epg_ctx->infos[i].last_version = (-1); + epg_ctx->last_sched_table_id = EITS_START_TID; + epg_ctx->o_last_sched_table_id = OEITS_START_TID; + + epg_ctx->pkt = av_packet_alloc(); + return epg_ctx->pkt ? 0 : AVERROR(ENOMEM); +} + +static av_cold int decode_end(AVCodecContext *avctx) +{ + EPGContext *epg_ctx = avctx->priv_data; + av_packet_free(&epg_ctx->pkt); + return 0; +} + +static const AVClass epg_class = { + .class_name = "EPG Decoder", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_epg_decoder = { + .name = "epg", + .long_name = NULL_IF_CONFIG_SMALL("EPG (Electronic Program Guide)"), + .type = AVMEDIA_TYPE_DATA, + .id = AV_CODEC_ID_EPG, + .priv_data_size = sizeof(EPGContext), + .init = decode_init, + .close = decode_end, + .receive_frame = epg_receive_frame, + .priv_class = &epg_class, +}; -- 2.23.0