On 12/30/2014 03:56 PM, Clément Bœsch wrote: > They are also probably useless since you can use av_asprintf() directly. > Thanks I didn't knew about that function.
Attached new patch with removing those function. -Anshul
>From 6adef31ca9b61e7d8bc9d94c10b0498bf3bcf85e Mon Sep 17 00:00:00 2001 From: Anshul Maheshwari <anshul.ffm...@gmail.com> Date: Tue, 30 Dec 2014 19:37:24 +0530 Subject: [PATCH] handle scte_35 messagecue --- ffmpeg.c | 46 +++++++- ffmpeg_opt.c | 9 +- libavcodec/Makefile | 2 + libavcodec/allcodecs.c | 2 + libavcodec/avcodec.h | 17 +++ libavcodec/codec_desc.c | 12 ++ libavcodec/cue_xml.c | 200 ++++++++++++++++++++++++++++++++ libavcodec/scte_35.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/scte_35.h | 31 +++++ libavcodec/utils.c | 33 +++++- libavformat/avformat.h | 16 +++ libavformat/mpegts.c | 45 +++++++- libavformat/utils.c | 1 + 13 files changed, 694 insertions(+), 14 deletions(-) create mode 100644 libavcodec/cue_xml.c create mode 100644 libavcodec/scte_35.c create mode 100644 libavcodec/scte_35.h diff --git a/ffmpeg.c b/ffmpeg.c index ddf4272..14712cd 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2063,6 +2063,44 @@ fail: return err < 0 ? err : ret; } +static int transcode_data(InputStream *ist, AVPacket *pkt, int *got_output) +{ + AVCodecContext *dec = ist->dec_ctx; + enum AVCodecID in_codec_id = AV_CODEC_ID_NONE; + AVData input; + AVData output; + AVPacket outpkt; + int ret, i; + + if (dec->codec) + in_codec_id = dec->codec->id; + + input.valid = 0; + update_benchmark(NULL); + ret = avcodec_decode_data(dec, &input, pkt); + update_benchmark("decode_data %d.%d", ist->file_index, ist->st->index); + *got_output = input.valid; + + if (ret < 0 || !input.valid) { + return ret; + } + for (i = 0; i < nb_output_streams && *got_output; i++) { + OutputStream *ost = output_streams[i]; + + if (!check_output_constraints(ist, ost) || !ost->encoding_needed + || ost->enc->type != AVMEDIA_TYPE_DATA) + continue; + ret = avcodec_encode_data(output_streams[i]->enc_ctx, &input, &output, in_codec_id); + av_init_packet(&outpkt); + outpkt.data = output.data; + outpkt.size = output.len; + write_frame(output_files[ost->file_index]->ctx, &outpkt, ost); + + } + + return ret; + +} static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output) { AVSubtitle subtitle; @@ -2203,6 +2241,9 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt) case AVMEDIA_TYPE_SUBTITLE: ret = transcode_subtitles(ist, &avpkt, &got_output); break; + case AVMEDIA_TYPE_DATA: + ret = transcode_data(ist, &avpkt, &got_output); + break; default: return -1; } @@ -2907,6 +2948,8 @@ static int transcode_init(void) enc_ctx->height = input_streams[ost->source_index]->st->codec->height; } break; + case AVMEDIA_TYPE_DATA: + break; default: abort(); break; @@ -3464,7 +3507,8 @@ static int process_input(int file_index) OutputStream *ost = output_streams[j]; if (ost->source_index == ifile->ist_index + i && - (ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE)) + (ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE + || ost->enc->type == AVMEDIA_TYPE_DATA )) finish_output_stream(ost); } } diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c index ac93eb5..f7b20fd 100644 --- a/ffmpeg_opt.c +++ b/ffmpeg_opt.c @@ -804,6 +804,7 @@ static int open_input_file(OptionsContext *o, const char *filename) char * video_codec_name = NULL; char * audio_codec_name = NULL; char *subtitle_codec_name = NULL; + char * data_codec_name = NULL; int scan_all_pmts_set = 0; if (o->format) { @@ -864,6 +865,8 @@ static int open_input_file(OptionsContext *o, const char *filename) find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE; ic->subtitle_codec_id= subtitle_codec_name ? find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE; + ic->data_codec_id = data_codec_name ? + find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)->id : AV_CODEC_ID_NONE; if (video_codec_name) av_format_set_video_codec (ic, find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)); @@ -871,6 +874,8 @@ static int open_input_file(OptionsContext *o, const char *filename) av_format_set_audio_codec (ic, find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)); if (subtitle_codec_name) av_format_set_subtitle_codec(ic, find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)); + if (data_codec_name) + av_format_set_data_codec(ic, find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)); ic->flags |= AVFMT_FLAG_NONBLOCK; ic->interrupt_callback = int_cb; @@ -1522,10 +1527,6 @@ static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int OutputStream *ost; ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index); - if (!ost->stream_copy) { - av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n"); - exit_program(1); - } return ost; } diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 107661b..c7cb069 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -293,6 +293,7 @@ OBJS-$(CONFIG_LOCO_DECODER) += loco.o OBJS-$(CONFIG_MACE3_DECODER) += mace.o OBJS-$(CONFIG_MACE6_DECODER) += mace.o OBJS-$(CONFIG_MDEC_DECODER) += mdec.o mpeg12.o mpeg12data.o +OBJS-$(CONFIG_CUE_XML_ENCODER) += cue_xml.o OBJS-$(CONFIG_METASOUND_DECODER) += metasound.o metasound_data.o \ twinvq.o OBJS-$(CONFIG_MICRODVD_DECODER) += microdvddec.o ass.o @@ -412,6 +413,7 @@ OBJS-$(CONFIG_SAMI_DECODER) += samidec.o ass.o OBJS-$(CONFIG_S302M_DECODER) += s302m.o OBJS-$(CONFIG_S302M_ENCODER) += s302menc.o OBJS-$(CONFIG_SANM_DECODER) += sanm.o +OBJS-$(CONFIG_SCTE_35_DECODER) += scte_35.o OBJS-$(CONFIG_SGI_DECODER) += sgidec.o OBJS-$(CONFIG_SGI_ENCODER) += sgienc.o rle.o OBJS-$(CONFIG_SGIRLE_DECODER) += sgirledec.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 8ceee2f..a965087 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -536,6 +536,8 @@ void avcodec_register_all(void) REGISTER_ENCODER(LIBAACPLUS, libaacplus); /* text */ + REGISTER_DECODER(SCTE_35, scte_35) + REGISTER_ENCODER(CUE_XML, cue_xml); REGISTER_DECODER(BINTEXT, bintext); REGISTER_DECODER(XBIN, xbin); REGISTER_DECODER(IDF, idf); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 99467bb..bd966d5 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -523,6 +523,8 @@ enum AVCodecID { /* other specific kind of codecs (generally used for attachments) */ AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. AV_CODEC_ID_TTF = 0x18000, + AV_CODEC_ID_SCTE_35 = MKBETAG('C','U','E','I'), + AV_CODEC_ID_CUE_XML = MKBETAG('C','U','E','X'), AV_CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'), AV_CODEC_ID_XBIN = MKBETAG('X','B','I','N'), AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), @@ -3157,6 +3159,13 @@ typedef struct AVCodecDefault AVCodecDefault; struct AVSubtitle; +typedef struct AVData { + void *data; + int len; + int ref_count; + int valid; +} AVData; + /** * AVCodec. */ @@ -3233,6 +3242,8 @@ typedef struct AVCodec { int (*init)(AVCodecContext *); int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, const struct AVSubtitle *sub); + int (*encode_data)(AVCodecContext *avctx, const AVData *input, AVData *output, + enum AVCodecID in_codec_id); /** * Encode data to an AVPacket. * @@ -3246,6 +3257,7 @@ typedef struct AVCodec { int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr); int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); + int (*decode_data)(AVCodecContext *,AVData *output, const AVPacket *avpkt); int (*close)(AVCodecContext *); /** * Flush buffers. @@ -4195,6 +4207,9 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt); +int avcodec_decode_data(AVCodecContext *avctx, + AVData *output, + const AVPacket *avpkt); /** * @defgroup lavc_parsing Frame parsing * @{ @@ -4585,6 +4600,8 @@ int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVSubtitle *sub); +int avcodec_encode_data(AVCodecContext *avctx,const AVData *input, AVData *output, + enum AVCodecID in_codec_id); /** diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 0af66f4..d26cd2f 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2739,6 +2739,18 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("binary data"), .mime_types= MT("application/octet-stream"), }, + { + .id = AV_CODEC_ID_SCTE_35, + .type = AVMEDIA_TYPE_DATA, + .name = "scte_35", + .long_name = NULL_IF_CONFIG_SMALL("SCTE 35 Message Queue"), + }, + { + .id = AV_CODEC_ID_CUE_XML, + .type = AVMEDIA_TYPE_DATA, + .name = "cue_xml", + .long_name = NULL_IF_CONFIG_SMALL("Message Queue to Insert Add"), + }, /* deprecated codec ids */ { diff --git a/libavcodec/cue_xml.c b/libavcodec/cue_xml.c new file mode 100644 index 0000000..1a5f470 --- /dev/null +++ b/libavcodec/cue_xml.c @@ -0,0 +1,200 @@ +/* + * SCTE 35 Cue Xml encoder + * Copyright (c) 2014 Anshul Maheshwaari + * + * 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 + */ +#include "avcodec.h" +#include "libavutil/opt.h" +#include "libavutil/bprint.h" +#include "scte_35.h" + +struct varList{ + char *var; + char *value; + struct varList *next; +}; +struct node { + char *name; + struct varList *vlist; + struct node *child; + struct node *parent; + struct node *sibling; +}; + +struct cue_xml_ctx { + AVClass *class; + struct node xml_tree; +}; +static void init_node(struct node* n,const char *name) +{ + n->name = av_strdup(name); + n->vlist = NULL; + n->child = NULL; + n->parent = NULL; + n->sibling = NULL; +} +static void add_child(struct node *parent, struct node* n) +{ + struct node *tmp; + + /* add to parent node + * parent keep only address of one child , other children are kept in sibling */ + if(!parent->child) + parent->child = n; + else { + tmp = parent->child; + while(tmp->sibling) { + tmp = tmp->sibling; + } + tmp->sibling = n; + } + n->parent = parent; +} + +/** + * memory of value need to be preallocated + */ +static int add_varval_pair(struct node* n,const char *var,const char *val) +{ + struct varList *pair; + + pair = av_mallocz(sizeof(*pair)); + if(!pair) + return AVERROR(ENOMEM); + + pair->var = av_strdup(var); + pair->value = val; + + if(!n->vlist) { + n->vlist = pair; + } else { + struct varList *npair = n->vlist; + while (npair->next) { + npair = npair->next; + } + npair->next = pair; + } + return 0; + +} +static int add_varval_pair_char(struct node* n,const char *var,const char *val) +{ + char *val2 = av_strdup(val); + return add_varval_pair(n, var, val2); +} + +static int add_varval_pair_uint32_t(struct node* n,const char *var,const uint32_t val) +{ + char *val2 = av_asprintf("%u", val);; + if(!val2) + return AVERROR(ENOMEM); + return add_varval_pair(n, var, val2); +} + +static int add_varval_pair_uint64_t(struct node* n,const char *var,const uint64_t val) +{ + char *val2 = av_asprintf("%llu", val); + if(!val2) + return AVERROR(ENOMEM); + return add_varval_pair(n, var, val2); +} +static void write_tree_as_data(struct node* root, AVData *data) +{ + AVBPrint buffer; + struct node *tmp = root->child; + struct node *leaf; + av_bprint_init(&buffer, 0, AV_BPRINT_SIZE_UNLIMITED); + + while(tmp) { + struct varList *npair = tmp->vlist; + av_bprintf(&buffer, "<%s", tmp->name); + while(npair) { + av_bprintf(&buffer, " %s=%s", npair->var, npair->value); + npair = npair->next; + } + av_bprintf(&buffer, ">\n"); + leaf = tmp; + tmp = tmp->child; + } + tmp = leaf; + while(tmp->parent) { + av_bprintf(&buffer, "</%s>\n", tmp->name); + tmp = tmp->parent; + } + data->data = av_strdup(buffer.str); + data->len = strlen(buffer.str); + data->valid = 1; + + av_log(NULL, AV_LOG_DEBUG, "%s\n",buffer.str); + av_bprint_finalize( &buffer, NULL); + +} +static av_cold int init_encoder(AVCodecContext *avctx) +{ + struct cue_xml_ctx *ctx = avctx->priv_data; + init_node(&ctx->xml_tree,"scte35"); + + return 0; +} +static av_cold int close_encoder(AVCodecContext *avctx) +{ + struct cue_xml_ctx *ctx = avctx->priv_data; + return 0; +} + +static int encode(AVCodecContext *avctx, const AVData *input, AVData *output, + enum AVCodecID in_codec_id) +{ + struct scte_35_interface *interface; + struct node event; + struct cue_xml_ctx *ctx = avctx->priv_data; + + if(in_codec_id != AV_CODEC_ID_SCTE_35) + return -1; + + interface = input->data; + init_node(&event,"event"); + add_varval_pair_uint32_t(&event, "event_id", interface->event_id); + add_varval_pair_uint32_t(&event, "duration", interface->duration); + add_varval_pair_uint64_t(&event, "pts", interface->pts); + add_child(&ctx->xml_tree, &event); + + write_tree_as_data(&ctx->xml_tree, output); + return 0; +} +static const AVOption options[] = { + {NULL} +}; +static const AVClass cue_xml_dec_class = { + .class_name = "SCTE 35 Decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_cue_xml_encoder = { + .name = "cue_xml", + .long_name = NULL_IF_CONFIG_SMALL("XML Message Queue Ad Insertion"), + .type = AVMEDIA_TYPE_DATA, + .id = AV_CODEC_ID_CUE_XML, + .priv_data_size = sizeof(struct cue_xml_ctx), + .init = init_encoder, + .close = close_encoder, + .encode_data = encode, + .priv_class = &cue_xml_dec_class, +}; diff --git a/libavcodec/scte_35.c b/libavcodec/scte_35.c new file mode 100644 index 0000000..2723225 --- /dev/null +++ b/libavcodec/scte_35.c @@ -0,0 +1,294 @@ +/* + * SCTE 35 decoder + * Copyright (c) 2014 Anshul Maheshwaari + * + * 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 + */ +#include "avcodec.h" +#include "bytestream.h" +#include "libavutil/opt.h" +#include "libavcodec/get_bits.h" +#include "libavcodec/scte_35.h" + +#define SCTE_CMD_NULL 0x00 +#define SCTE_CMD_SCHEDULE 0x04 +#define SCTE_CMD_INSERT 0x05 +#define SCTE_CMD_SIGNAL 0x06 +#define SCTE_CMD_BANDWIDTH_RESERVATION 0x07 +struct scte_35_ctx { + AVClass *class; + uint64_t pts_adjustment; + uint32_t event_id; + int component_tag; + int64_t duration; + uint16_t u_program_id; + uint8_t avail_num; + uint8_t avail_expect; + /* flags */ + int splice_event_cancel_indicator; + int out_of_network_indicator; + int program_splice_flag; + int duration_flag; + int splice_immediate_flag; + int auto_return; +}; +static av_cold int init_decoder(AVCodecContext *avctx) +{ + struct scte_35_ctx *ctx = avctx->priv_data; + return 0; +} +static av_cold int close_decoder(AVCodecContext *avctx) +{ + struct scte_35_ctx *ctx = avctx->priv_data; + return 0; +} + +/** + * save the parsed time in ctx pts_time + @return length of buffer consumed +*/ +static int parse_splice_time(struct scte_35_ctx *ctx, const uint8_t *buf, uint64_t *pts) +{ + GetBitContext gb; + int ret; + init_get_bits(&gb, buf, 40); + /* is time specified */ + ret = get_bits(&gb, 1); + if(ret) { + skip_bits(&gb, 6); + *pts = get_bits64(&gb,33) + ctx->pts_adjustment; + av_log(ctx, AV_LOG_DEBUG, "time = %lld\n", *pts/90000); + return 5; + } else { + skip_bits(&gb, 7); + return 1; + } +} +static int parse_schedule_cmd(struct scte_35_ctx *ctx, const uint8_t *buf) +{ + const uint8_t *sbuf = buf; + av_log(ctx, AV_LOG_DEBUG, "Schedule cmd\n"); + return buf - sbuf; +} +/** + @return length of buffer used + */ +static int parse_insert_cmd(struct scte_35_ctx *ctx, const uint8_t *buf, AVData *output) +{ + GetBitContext gb; + int ret; + const uint8_t *sbuf = buf; + struct scte_35_interface *iface; + + iface = av_mallocz(sizeof(struct scte_35_interface)); + if(!iface) + return AVERROR(ENOMEM); + output->data = iface; + output->valid = 1; + + av_log(ctx, AV_LOG_DEBUG, "Insert cmd\n"); + ctx->event_id = AV_RB32(buf); + av_log(ctx, AV_LOG_DEBUG, "event_id = %x\n", ctx->event_id); + buf +=4; + ctx->splice_event_cancel_indicator = *buf & 0x80; + av_log(ctx, AV_LOG_DEBUG, "splice_event_cancel_indicator = %d\n", ctx->splice_event_cancel_indicator); + buf++; + + iface->event_id = ctx->event_id; + if (!ctx->splice_event_cancel_indicator) { + init_get_bits(&gb, buf, 8); + ctx->out_of_network_indicator = get_bits(&gb, 1); + ctx->program_splice_flag = get_bits(&gb, 1); + ctx->duration_flag = get_bits(&gb, 1); + ctx->splice_immediate_flag = get_bits(&gb, 1); + skip_bits(&gb, 4); + + } + buf++; + + + av_log(ctx, AV_LOG_DEBUG, "out_of_network_indicator = %d\n", ctx->out_of_network_indicator); + av_log(ctx, AV_LOG_DEBUG, "program_splice_flag = %d\n", ctx->program_splice_flag); + av_log(ctx, AV_LOG_DEBUG, "duration_flag = %d\n", ctx->duration_flag); + av_log(ctx, AV_LOG_DEBUG, "splice_immediate_flag = %d\n", ctx->splice_immediate_flag); + + if (ctx->program_splice_flag && !ctx->splice_immediate_flag) { + ret = parse_splice_time(ctx, buf, &iface->pts); + buf += ret; + } + if ( ctx->program_splice_flag == 0) { + int comp_cnt = *buf++; + int i; + av_log(ctx, AV_LOG_DEBUG, "component_count = %d\n", comp_cnt); + for ( i = 0; i < comp_cnt; i++) { + ctx->component_tag = *buf++; + av_log(ctx, AV_LOG_DEBUG, "component_tag = %d\n", ctx->component_tag); + if (ctx->splice_immediate_flag) { + ret = parse_splice_time(ctx, buf, &iface->pts); + buf += ret; + } + } + } + if ( ctx->duration_flag ) { + init_get_bits(&gb, buf, 40); + ctx->auto_return = get_bits(&gb, 1); + av_log(ctx, AV_LOG_DEBUG, "autoreturn = %d\n", ctx->auto_return); + skip_bits(&gb, 6); + ctx->duration = get_bits64(&gb,33) + ctx->pts_adjustment; + av_log(ctx, AV_LOG_DEBUG, "duration = %lld\n", ctx->duration/90000); + buf += 5; + } + ctx->u_program_id = AV_RB16(buf); + av_log(ctx, AV_LOG_DEBUG, "u_program_id = %hd\n", ctx->u_program_id); + buf += 2; + ctx->avail_num = *buf++; + av_log(ctx, AV_LOG_DEBUG, "avail_num = %hhd\n", ctx->avail_num); + ctx->avail_expect = *buf++; + av_log(ctx, AV_LOG_DEBUG, "avail_expect = %hhd\n", ctx->avail_expect); + + return buf - sbuf; +} +static int parse_time_signal_cmd(struct scte_35_ctx *ctx, const uint8_t *buf) +{ + const uint8_t *sbuf = buf; + av_log(ctx, AV_LOG_DEBUG, "Time Signal cmd\n"); + return buf - sbuf; +} +static int parse_bandwidth_reservation_cmd(struct scte_35_ctx *ctx, const uint8_t *buf) +{ + const uint8_t *sbuf = buf; + av_log(ctx, AV_LOG_DEBUG, "Band Width reservation cmd\n"); + return buf - sbuf; +} + +static int decode(AVCodecContext *avctx, AVData *output, + const AVPacket *avpkt) +{ + struct scte_35_ctx *ctx = avctx->priv_data; + const uint8_t *buf = avpkt->data; + int len = avpkt->size; + int section_length; + int cmd_length; + uint8_t cmd_type; + int16_t tier; + GetBitContext gb; + int ret; + + if (!buf) + return AVERROR_EOF; + + /* check table id */ + if (*buf != 0xfc) + av_log(ctx, AV_LOG_ERROR, "Invalid SCTE packet\n"); + + init_get_bits(&gb, buf + 1, 104); + + /* section_syntax_indicator should be 0 */ + ret = get_bits(&gb,1); + if (ret) + av_log(ctx, AV_LOG_WARNING, "Section indicator should be 0, since MPEG short sections are to be used.\n"); + + /* private indicator */ + ret = get_bits(&gb,1); + if (ret) + av_log(ctx, AV_LOG_WARNING, "corrupt packet\n"); + + skip_bits(&gb,2); + + /* section length may be there */ + section_length = get_bits(&gb,12); + if( section_length > 4093) + if(ret) { + av_log(ctx, AV_LOG_ERROR, "Invalid length of section\n"); + return AVERROR_INVALIDDATA; + } + + /* protocol version */ + skip_bits(&gb,8); + + ret = get_bits(&gb,1); + if(ret) { + av_log(ctx, AV_LOG_ERROR, "Encrytion not yet supported\n"); + return AVERROR_PATCHWELCOME; + } + /* encryption algo */ + skip_bits(&gb,6); + + ctx->pts_adjustment = get_bits64(&gb, 33); + + /* cw_index: used in encryption */ + skip_bits(&gb,8); + + + /* tier */ + tier = get_bits(&gb,12); + if( (tier & 0xfff) == 0xfff) + tier = -1; + + cmd_length = get_bits(&gb,12); + if((cmd_length & 0xfff) == 0xfff ) + cmd_length = -1; + + cmd_type = get_bits(&gb,8); + switch(cmd_type) { + case SCTE_CMD_NULL: + av_log(ctx, AV_LOG_DEBUG, "NULL packet\n"); + break; + case SCTE_CMD_SCHEDULE: + ret = parse_schedule_cmd(ctx, buf + 14); + break; + case SCTE_CMD_INSERT: + ret = parse_insert_cmd(ctx, buf + 14, output); + break; + case SCTE_CMD_SIGNAL: + ret = parse_time_signal_cmd(ctx, buf + 14); + break; + case SCTE_CMD_BANDWIDTH_RESERVATION: + ret = parse_bandwidth_reservation_cmd(ctx, buf + 14); + break; + default: + break; + /* reserved yet */ + } + if(ret < 0) + goto fail; + buf += ret; + +fail: + return ret; +} +static const AVOption options[] = { + {NULL} +}; +static const AVClass scte_35_dec_class = { + .class_name = "SCTE 35 Decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_scte_35_decoder = { + .name = "scte_35", + .long_name = NULL_IF_CONFIG_SMALL("SCTE 35"), + .type = AVMEDIA_TYPE_DATA, + .id = AV_CODEC_ID_SCTE_35, + .priv_data_size = sizeof(struct scte_35_ctx), + .init = init_decoder, + .close = close_decoder, + .decode_data = decode, + .priv_class = &scte_35_dec_class, +}; diff --git a/libavcodec/scte_35.h b/libavcodec/scte_35.h new file mode 100644 index 0000000..63bbac5 --- /dev/null +++ b/libavcodec/scte_35.h @@ -0,0 +1,31 @@ +/* + * SCTE 35 decoder + * Copyright (c) 2014 Anshul Maheshwaari + * + * 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 + */ +#ifndef SCTE_35_H +#define SCTE_35_H +struct scte_35_interface { + int32_t event_id; + uint64_t pts; + int64_t duration; + /* flag */ + int inout; + int cancel; +}; +#endif diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 1ec5cae..bdbc0a4 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -186,12 +186,12 @@ static av_cold void avcodec_init(void) int av_codec_is_encoder(const AVCodec *codec) { - return codec && (codec->encode_sub || codec->encode2); + return codec && (codec->encode_sub || codec->encode2 || codec->encode_data); } int av_codec_is_decoder(const AVCodec *codec) { - return codec && codec->decode; + return codec && ( codec->decode || codec->decode_data); } av_cold void avcodec_register(AVCodec *codec) @@ -2173,7 +2173,14 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, avctx->frame_number++; return ret; } - +int avcodec_encode_data(AVCodecContext *avctx, const AVData *input, AVData *output, + enum AVCodecID in_codec_id) +{ + int ret; + ret = avctx->codec->encode_data(avctx, input, output, in_codec_id); + avctx->frame_number++; + return ret; +} /** * Attempt to guess proper monotonic timestamps for decoded video frames * which might have incorrect times. Input timestamps may wrap around, in @@ -2624,6 +2631,26 @@ fail: return ret; } +int attribute_align_arg avcodec_decode_data(AVCodecContext *avctx, + AVData *output, + const AVPacket *avpkt) +{ + AVCodecInternal *avci = avctx->internal; + int ret = 0; + + if (!avctx->codec) + return AVERROR(EINVAL); + if (avctx->codec->type != AVMEDIA_TYPE_DATA) { + av_log(avctx, AV_LOG_ERROR, "Invalid media type for data\n"); + return AVERROR(EINVAL); + } + + ret = avctx->codec->decode_data(avctx, output, avpkt); + + return ret; + + +} #define UTF8_MAX_BYTES 4 /* 5 and 6 bytes sequences should not be used */ static int recode_subtitle(AVCodecContext *avctx, AVPacket *outpkt, const AVPacket *inpkt) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 2e54ed1..7fd96ac 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1367,6 +1367,12 @@ typedef struct AVFormatContext { enum AVCodecID subtitle_codec_id; /** + * Forced Data codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID data_codec_id; + + /** * Maximum amount of memory in bytes to use for the index of each stream. * If the index exceeds this size, entries will be discarded as * needed to maintain a smaller size. This can lead to slower or less @@ -1705,6 +1711,14 @@ typedef struct AVFormatContext { AVCodec *subtitle_codec; /** + * Forced data codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_data_codec (NO direct access). + */ + AVCodec *data_codec; + + /** * Number of bytes to be written as padding in a metadata header. * Demuxing: Unused. * Muxing: Set by user via av_format_set_metadata_header_padding. @@ -1764,6 +1778,8 @@ AVCodec * av_format_get_audio_codec(const AVFormatContext *s); void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_data_codec(const AVFormatContext *s); +void av_format_set_data_codec(AVFormatContext *s, AVCodec *c); int av_format_get_metadata_header_padding(const AVFormatContext *s); void av_format_set_metadata_header_padding(AVFormatContext *s, int c); void * av_format_get_opaque(const AVFormatContext *s); diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index f61388b..6971e93 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -57,6 +57,7 @@ enum MpegTSFilterType { MPEGTS_PES, MPEGTS_SECTION, MPEGTS_PCR, + MPEGTS_DATA, }; typedef struct MpegTSFilter MpegTSFilter; @@ -498,6 +499,11 @@ static MpegTSFilter *mpegts_open_pcr_filter(MpegTSContext *ts, unsigned int pid) return mpegts_open_filter(ts, pid, MPEGTS_PCR); } +static MpegTSFilter *mpegts_open_data_filter(MpegTSContext *ts, unsigned int pid) +{ + return mpegts_open_filter(ts, pid, MPEGTS_DATA); +} + static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter) { int pid; @@ -676,6 +682,7 @@ static const StreamType ISO_types[] = { { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, + { 0x86, AVMEDIA_TYPE_DATA, AV_CODEC_ID_SCTE_35 }, { 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, { 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, { 0 }, @@ -824,6 +831,12 @@ static void reset_pes_packet_state(PESContext *pes) av_buffer_unref(&pes->buffer); } +static void new_data_packet(const uint8_t *buffer, int len, AVPacket *pkt) +{ + av_init_packet(pkt); + pkt->data = buffer; + pkt->size = len; +} static void new_pes_packet(PESContext *pes, AVPacket *pkt) { av_init_packet(pkt); @@ -1886,7 +1899,20 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len pes->st->id = pes->pid; } st = pes->st; - } else if (stream_type != 0x13) { + } else if (stream_type == 0x86 ) { + int idx = ff_find_stream_index(ts->stream, pid); + if (idx >= 0) { + st = ts->stream->streams[idx]; + } else { + st = avformat_new_stream(ts->stream, NULL); + if (!st) + goto out; + st->id = pid; + st->codec->codec_type = AVMEDIA_TYPE_DATA; + mpegts_find_stream_type(st, stream_type, ISO_types); + mpegts_open_data_filter(ts, pid); + } + }else if (stream_type != 0x13 ) { if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid); @@ -2222,14 +2248,17 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) } } - } else { + } else if (tss->type == MPEGTS_DATA) { + /* may be pointer field is 0 and to be ignored*/ + p++; + new_data_packet(p,p_end - p, ts->pkt); + ts->stop_parse = 1; + } else if (tss->type == MPEGTS_PES) { int ret; // Note: The position here points actually behind the current packet. - if (tss->type == MPEGTS_PES) { - if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, + if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, pos - ts->raw_packet_size)) < 0) - return ret; - } + return ret; } return 0; @@ -2616,6 +2645,10 @@ static int mpegts_read_packet(AVFormatContext *s, AVPacket *pkt) ret = 0; break; } + } else if (ts->pids[i] && ts->pids[i]->type == MPEGTS_DATA) { + // ret = 0; + //ts->pkt->size = 0; + return ret; } } diff --git a/libavformat/utils.c b/libavformat/utils.c index 752270d..b8fef74 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -110,6 +110,7 @@ MAKE_ACCESSORS(AVStream, stream, char *, recommended_encoder_configuration) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_codec) +MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, data_codec) MAKE_ACCESSORS(AVFormatContext, format, int, metadata_header_padding) MAKE_ACCESSORS(AVFormatContext, format, void *, opaque) MAKE_ACCESSORS(AVFormatContext, format, av_format_control_message, control_message_cb) -- 1.8.1.4
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel