* commit '33d18982fa03feb061c8f744a4f0a9175c1f63ab': lavc: add a new bitstream filtering API Conversions-by: Hendrik Leppkes <h.leppkes@gmail.com> Conversions-by: Derek Buitenguis <derek.buitenhuis@gmail.com> Merged-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>tags/n3.1
| @@ -3204,7 +3204,6 @@ ENCODER_LIST=$(find_things encoder ENC libavcodec/allcodecs.c) | |||||
| DECODER_LIST=$(find_things decoder DEC libavcodec/allcodecs.c) | DECODER_LIST=$(find_things decoder DEC libavcodec/allcodecs.c) | ||||
| HWACCEL_LIST=$(find_things hwaccel HWACCEL libavcodec/allcodecs.c) | HWACCEL_LIST=$(find_things hwaccel HWACCEL libavcodec/allcodecs.c) | ||||
| PARSER_LIST=$(find_things parser PARSER libavcodec/allcodecs.c) | PARSER_LIST=$(find_things parser PARSER libavcodec/allcodecs.c) | ||||
| BSF_LIST=$(find_things bsf BSF libavcodec/allcodecs.c) | |||||
| MUXER_LIST=$(find_things muxer _MUX libavformat/allformats.c) | MUXER_LIST=$(find_things muxer _MUX libavformat/allformats.c) | ||||
| DEMUXER_LIST=$(find_things demuxer DEMUX libavformat/allformats.c) | DEMUXER_LIST=$(find_things demuxer DEMUX libavformat/allformats.c) | ||||
| OUTDEV_LIST=$(find_things outdev OUTDEV libavdevice/alldevices.c) | OUTDEV_LIST=$(find_things outdev OUTDEV libavdevice/alldevices.c) | ||||
| @@ -3218,6 +3217,7 @@ find_things_extern(){ | |||||
| sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$thing/p" "$file" | sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$thing/p" "$file" | ||||
| } | } | ||||
| BSF_LIST=$(find_things_extern bsf AVBitStreamFilter libavcodec/bitstream_filters.c) | |||||
| PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c) | PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c) | ||||
| ALL_COMPONENTS=" | ALL_COMPONENTS=" | ||||
| @@ -15,6 +15,10 @@ libavutil: 2015-08-28 | |||||
| API changes, most recent first: | API changes, most recent first: | ||||
| 2016-xx-xx - xxxxxxx - lavc 57.15.0 - avcodec.h | |||||
| Add a new bitstream filtering API working with AVPackets. | |||||
| Deprecate the old bistream filtering API. | |||||
| 2016-xx-xx - xxxxxxx - lavfi 6.42.0 - avfilter.h | 2016-xx-xx - xxxxxxx - lavfi 6.42.0 - avfilter.h | ||||
| Add AVFilterContext.hw_device_ctx. | Add AVFilterContext.hw_device_ctx. | ||||
| @@ -26,6 +26,8 @@ OBJS = allcodecs.o \ | |||||
| avpicture.o \ | avpicture.o \ | ||||
| bitstream.o \ | bitstream.o \ | ||||
| bitstream_filter.o \ | bitstream_filter.o \ | ||||
| bitstream_filters.o \ | |||||
| bsf.o \ | |||||
| codec_desc.o \ | codec_desc.o \ | ||||
| d3d11va.o \ | d3d11va.o \ | ||||
| dirac.o \ | dirac.o \ | ||||
| @@ -21,6 +21,7 @@ | |||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "aacadtsdec.h" | #include "aacadtsdec.h" | ||||
| #include "bsf.h" | |||||
| #include "put_bits.h" | #include "put_bits.h" | ||||
| #include "get_bits.h" | #include "get_bits.h" | ||||
| #include "mpeg4audio.h" | #include "mpeg4audio.h" | ||||
| @@ -34,68 +35,75 @@ typedef struct AACBSFContext { | |||||
| * This filter creates an MPEG-4 AudioSpecificConfig from an MPEG-2/4 | * This filter creates an MPEG-4 AudioSpecificConfig from an MPEG-2/4 | ||||
| * ADTS header and removes the ADTS header. | * ADTS header and removes the ADTS header. | ||||
| */ | */ | ||||
| static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) | |||||
| { | { | ||||
| AACBSFContext *ctx = bsfc->priv_data; | |||||
| GetBitContext gb; | GetBitContext gb; | ||||
| PutBitContext pb; | PutBitContext pb; | ||||
| AACADTSHeaderInfo hdr; | AACADTSHeaderInfo hdr; | ||||
| AVPacket *in; | |||||
| int ret; | |||||
| AACBSFContext *ctx = bsfc->priv_data; | |||||
| ret = ff_bsf_get_packet(bsfc, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| init_get_bits(&gb, buf, AAC_ADTS_HEADER_SIZE*8); | |||||
| if (in->size < AAC_ADTS_HEADER_SIZE) | |||||
| goto packet_too_small; | |||||
| *poutbuf = (uint8_t*) buf; | |||||
| *poutbuf_size = buf_size; | |||||
| init_get_bits(&gb, in->data, AAC_ADTS_HEADER_SIZE * 8); | |||||
| if (avctx->extradata) | |||||
| if (show_bits(&gb, 12) != 0xfff) | |||||
| return 0; | |||||
| if (bsfc->par_in->extradata && show_bits(&gb, 12) != 0xfff) | |||||
| goto finish; | |||||
| if (avpriv_aac_parse_header(&gb, &hdr) < 0) { | if (avpriv_aac_parse_header(&gb, &hdr) < 0) { | ||||
| av_log(avctx, AV_LOG_ERROR, "Error parsing ADTS frame header!\n"); | |||||
| return AVERROR_INVALIDDATA; | |||||
| av_log(bsfc, AV_LOG_ERROR, "Error parsing ADTS frame header!\n"); | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| goto fail; | |||||
| } | } | ||||
| if (!hdr.crc_absent && hdr.num_aac_frames > 1) { | if (!hdr.crc_absent && hdr.num_aac_frames > 1) { | ||||
| avpriv_report_missing_feature(avctx, | |||||
| avpriv_report_missing_feature(bsfc, | |||||
| "Multiple RDBs per frame with CRC"); | "Multiple RDBs per frame with CRC"); | ||||
| return AVERROR_PATCHWELCOME; | |||||
| ret = AVERROR_PATCHWELCOME; | |||||
| goto fail; | |||||
| } | } | ||||
| buf += AAC_ADTS_HEADER_SIZE + 2*!hdr.crc_absent; | |||||
| buf_size -= AAC_ADTS_HEADER_SIZE + 2*!hdr.crc_absent; | |||||
| in->size -= AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; | |||||
| if (in->size <= 0) | |||||
| goto packet_too_small; | |||||
| in->data += AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; | |||||
| if (!ctx->first_frame_done) { | if (!ctx->first_frame_done) { | ||||
| int pce_size = 0; | int pce_size = 0; | ||||
| uint8_t pce_data[MAX_PCE_SIZE]; | uint8_t pce_data[MAX_PCE_SIZE]; | ||||
| uint8_t *extradata; | |||||
| if (!hdr.chan_config) { | if (!hdr.chan_config) { | ||||
| init_get_bits(&gb, buf, buf_size * 8); | |||||
| init_get_bits(&gb, in->data, in->size * 8); | |||||
| if (get_bits(&gb, 3) != 5) { | if (get_bits(&gb, 3) != 5) { | ||||
| avpriv_report_missing_feature(avctx, | |||||
| avpriv_report_missing_feature(bsfc, | |||||
| "PCE-based channel configuration " | "PCE-based channel configuration " | ||||
| "without PCE as first syntax " | "without PCE as first syntax " | ||||
| "element"); | "element"); | ||||
| return AVERROR_PATCHWELCOME; | |||||
| ret = AVERROR_PATCHWELCOME; | |||||
| goto fail; | |||||
| } | } | ||||
| init_put_bits(&pb, pce_data, MAX_PCE_SIZE); | init_put_bits(&pb, pce_data, MAX_PCE_SIZE); | ||||
| pce_size = avpriv_copy_pce_data(&pb, &gb)/8; | pce_size = avpriv_copy_pce_data(&pb, &gb)/8; | ||||
| flush_put_bits(&pb); | flush_put_bits(&pb); | ||||
| buf_size -= get_bits_count(&gb)/8; | |||||
| buf += get_bits_count(&gb)/8; | |||||
| in->size -= get_bits_count(&gb)/8; | |||||
| in->data += get_bits_count(&gb)/8; | |||||
| } | } | ||||
| av_free(avctx->extradata); | |||||
| avctx->extradata_size = 2 + pce_size; | |||||
| avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!avctx->extradata) { | |||||
| avctx->extradata_size = 0; | |||||
| return AVERROR(ENOMEM); | |||||
| extradata = av_mallocz(2 + pce_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!extradata) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | } | ||||
| init_put_bits(&pb, avctx->extradata, avctx->extradata_size); | |||||
| init_put_bits(&pb, extradata, 2 + pce_size); | |||||
| put_bits(&pb, 5, hdr.object_type); | put_bits(&pb, 5, hdr.object_type); | ||||
| put_bits(&pb, 4, hdr.sampling_index); | put_bits(&pb, 4, hdr.sampling_index); | ||||
| put_bits(&pb, 4, hdr.chan_config); | put_bits(&pb, 4, hdr.chan_config); | ||||
| @@ -104,20 +112,44 @@ static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc, | |||||
| put_bits(&pb, 1, 0); //is not extension | put_bits(&pb, 1, 0); //is not extension | ||||
| flush_put_bits(&pb); | flush_put_bits(&pb); | ||||
| if (pce_size) { | if (pce_size) { | ||||
| memcpy(avctx->extradata + 2, pce_data, pce_size); | |||||
| memcpy(extradata + 2, pce_data, pce_size); | |||||
| } | } | ||||
| bsfc->par_out->extradata = extradata; | |||||
| bsfc->par_out->extradata_size = 2 + pce_size; | |||||
| ctx->first_frame_done = 1; | ctx->first_frame_done = 1; | ||||
| } | } | ||||
| *poutbuf = (uint8_t*) buf; | |||||
| *poutbuf_size = buf_size; | |||||
| finish: | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| return 0; | return 0; | ||||
| packet_too_small: | |||||
| av_log(bsfc, AV_LOG_ERROR, "Input packet too small\n"); | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| fail: | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_aac_adtstoasc_bsf = { | |||||
| static int aac_adtstoasc_init(AVBSFContext *ctx) | |||||
| { | |||||
| av_freep(&ctx->par_out->extradata); | |||||
| ctx->par_out->extradata_size = 0; | |||||
| return 0; | |||||
| } | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_AAC, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_aac_adtstoasc_bsf = { | |||||
| .name = "aac_adtstoasc", | .name = "aac_adtstoasc", | ||||
| .priv_data_size = sizeof(AACBSFContext), | .priv_data_size = sizeof(AACBSFContext), | ||||
| .init = aac_adtstoasc_init, | |||||
| .filter = aac_adtstoasc_filter, | .filter = aac_adtstoasc_filter, | ||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -58,13 +58,6 @@ | |||||
| av_register_codec_parser(&ff_##x##_parser); \ | av_register_codec_parser(&ff_##x##_parser); \ | ||||
| } | } | ||||
| #define REGISTER_BSF(X, x) \ | |||||
| { \ | |||||
| extern AVBitStreamFilter ff_##x##_bsf; \ | |||||
| if (CONFIG_##X##_BSF) \ | |||||
| av_register_bitstream_filter(&ff_##x##_bsf); \ | |||||
| } | |||||
| void avcodec_register_all(void) | void avcodec_register_all(void) | ||||
| { | { | ||||
| static int initialized; | static int initialized; | ||||
| @@ -667,22 +660,4 @@ void avcodec_register_all(void) | |||||
| REGISTER_PARSER(VP3, vp3); | REGISTER_PARSER(VP3, vp3); | ||||
| REGISTER_PARSER(VP8, vp8); | REGISTER_PARSER(VP8, vp8); | ||||
| REGISTER_PARSER(VP9, vp9); | REGISTER_PARSER(VP9, vp9); | ||||
| /* bitstream filters */ | |||||
| REGISTER_BSF(AAC_ADTSTOASC, aac_adtstoasc); | |||||
| REGISTER_BSF(CHOMP, chomp); | |||||
| REGISTER_BSF(DUMP_EXTRADATA, dump_extradata); | |||||
| REGISTER_BSF(DCA_CORE, dca_core); | |||||
| REGISTER_BSF(H264_MP4TOANNEXB, h264_mp4toannexb); | |||||
| REGISTER_BSF(HEVC_MP4TOANNEXB, hevc_mp4toannexb); | |||||
| REGISTER_BSF(IMX_DUMP_HEADER, imx_dump_header); | |||||
| REGISTER_BSF(MJPEG2JPEG, mjpeg2jpeg); | |||||
| REGISTER_BSF(MJPEGA_DUMP_HEADER, mjpega_dump_header); | |||||
| REGISTER_BSF(MP3_HEADER_DECOMPRESS, mp3_header_decompress); | |||||
| REGISTER_BSF(MPEG4_UNPACK_BFRAMES, mpeg4_unpack_bframes); | |||||
| REGISTER_BSF(MOV2TEXTSUB, mov2textsub); | |||||
| REGISTER_BSF(NOISE, noise); | |||||
| REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata); | |||||
| REGISTER_BSF(TEXT2MOVSUB, text2movsub); | |||||
| REGISTER_BSF(VP9_SUPERFRAME, vp9_superframe); | |||||
| } | } | ||||
| @@ -5386,7 +5386,7 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); | |||||
| */ | */ | ||||
| int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes); | int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes); | ||||
| #if FF_API_OLD_BSF | |||||
| typedef struct AVBitStreamFilterContext { | typedef struct AVBitStreamFilterContext { | ||||
| void *priv_data; | void *priv_data; | ||||
| struct AVBitStreamFilter *filter; | struct AVBitStreamFilter *filter; | ||||
| @@ -5398,19 +5398,102 @@ typedef struct AVBitStreamFilterContext { | |||||
| */ | */ | ||||
| char *args; | char *args; | ||||
| } AVBitStreamFilterContext; | } AVBitStreamFilterContext; | ||||
| #endif | |||||
| typedef struct AVBSFInternal AVBSFInternal; | |||||
| /** | |||||
| * The bitstream filter state. | |||||
| * | |||||
| * This struct must be allocated with av_bsf_alloc() and freed with | |||||
| * av_bsf_free(). | |||||
| * | |||||
| * The fields in the struct will only be changed (by the caller or by the | |||||
| * filter) as described in their documentation, and are to be considered | |||||
| * immutable otherwise. | |||||
| */ | |||||
| typedef struct AVBSFContext { | |||||
| /** | |||||
| * A class for logging and AVOptions | |||||
| */ | |||||
| const AVClass *av_class; | |||||
| /** | |||||
| * The bitstream filter this context is an instance of. | |||||
| */ | |||||
| const struct AVBitStreamFilter *filter; | |||||
| /** | |||||
| * Opaque libavcodec internal data. Must not be touched by the caller in any | |||||
| * way. | |||||
| */ | |||||
| AVBSFInternal *internal; | |||||
| /** | |||||
| * Opaque filter-specific private data. If filter->priv_class is non-NULL, | |||||
| * this is an AVOptions-enabled struct. | |||||
| */ | |||||
| void *priv_data; | |||||
| /** | |||||
| * Parameters of the input stream. Set by the caller before av_bsf_init(). | |||||
| */ | |||||
| AVCodecParameters *par_in; | |||||
| /** | |||||
| * Parameters of the output stream. Set by the filter in av_bsf_init(). | |||||
| */ | |||||
| AVCodecParameters *par_out; | |||||
| /** | |||||
| * The timebase used for the timestamps of the input packets. Set by the | |||||
| * caller before av_bsf_init(). | |||||
| */ | |||||
| AVRational time_base_in; | |||||
| /** | |||||
| * The timebase used for the timestamps of the output packets. Set by the | |||||
| * filter in av_bsf_init(). | |||||
| */ | |||||
| AVRational time_base_out; | |||||
| } AVBSFContext; | |||||
| typedef struct AVBitStreamFilter { | typedef struct AVBitStreamFilter { | ||||
| const char *name; | const char *name; | ||||
| /** | |||||
| * A list of codec ids supported by the filter, terminated by | |||||
| * AV_CODEC_ID_NONE. | |||||
| * May be NULL, in that case the bitstream filter works with any codec id. | |||||
| */ | |||||
| const enum AVCodecID *codec_ids; | |||||
| /** | |||||
| * A class for the private data, used to declare bitstream filter private | |||||
| * AVOptions. This field is NULL for bitstream filters that do not declare | |||||
| * any options. | |||||
| * | |||||
| * If this field is non-NULL, the first member of the filter private data | |||||
| * must be a pointer to AVClass, which will be set by libavcodec generic | |||||
| * code to this class. | |||||
| */ | |||||
| const AVClass *priv_class; | |||||
| /***************************************************************** | |||||
| * No fields below this line are part of the public API. They | |||||
| * may not be used outside of libavcodec and can be changed and | |||||
| * removed at will. | |||||
| * New public fields should be added right above. | |||||
| ***************************************************************** | |||||
| */ | |||||
| int priv_data_size; | int priv_data_size; | ||||
| int (*filter)(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe); | |||||
| void (*close)(AVBitStreamFilterContext *bsfc); | |||||
| struct AVBitStreamFilter *next; | |||||
| int (*init)(AVBSFContext *ctx); | |||||
| int (*filter)(AVBSFContext *ctx, AVPacket *pkt); | |||||
| void (*close)(AVBSFContext *ctx); | |||||
| } AVBitStreamFilter; | } AVBitStreamFilter; | ||||
| #if FF_API_OLD_BSF | |||||
| /** | /** | ||||
| * Register a bitstream filter. | * Register a bitstream filter. | ||||
| * | * | ||||
| @@ -5420,6 +5503,7 @@ typedef struct AVBitStreamFilter { | |||||
| * | * | ||||
| * @see avcodec_register_all() | * @see avcodec_register_all() | ||||
| */ | */ | ||||
| attribute_deprecated | |||||
| void av_register_bitstream_filter(AVBitStreamFilter *bsf); | void av_register_bitstream_filter(AVBitStreamFilter *bsf); | ||||
| /** | /** | ||||
| @@ -5432,6 +5516,7 @@ void av_register_bitstream_filter(AVBitStreamFilter *bsf); | |||||
| * @return a bitstream filter context if a matching filter was found | * @return a bitstream filter context if a matching filter was found | ||||
| * and successfully initialized, NULL otherwise | * and successfully initialized, NULL otherwise | ||||
| */ | */ | ||||
| attribute_deprecated | |||||
| AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); | AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); | ||||
| /** | /** | ||||
| @@ -5463,6 +5548,7 @@ AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); | |||||
| * its starting address). A special case is if *poutbuf was set to NULL and | * its starting address). A special case is if *poutbuf was set to NULL and | ||||
| * *poutbuf_size was set to 0, which indicates the packet should be dropped. | * *poutbuf_size was set to 0, which indicates the packet should be dropped. | ||||
| */ | */ | ||||
| attribute_deprecated | |||||
| int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, | int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, | ||||
| AVCodecContext *avctx, const char *args, | AVCodecContext *avctx, const char *args, | ||||
| uint8_t **poutbuf, int *poutbuf_size, | uint8_t **poutbuf, int *poutbuf_size, | ||||
| @@ -5474,6 +5560,7 @@ int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, | |||||
| * @param bsf the bitstream filter context created with | * @param bsf the bitstream filter context created with | ||||
| * av_bitstream_filter_init(), can be NULL | * av_bitstream_filter_init(), can be NULL | ||||
| */ | */ | ||||
| attribute_deprecated | |||||
| void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); | void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); | ||||
| /** | /** | ||||
| @@ -5484,7 +5571,103 @@ void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); | |||||
| * This function can be used to iterate over all registered bitstream | * This function can be used to iterate over all registered bitstream | ||||
| * filters. | * filters. | ||||
| */ | */ | ||||
| attribute_deprecated | |||||
| AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); | AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); | ||||
| #endif | |||||
| /** | |||||
| * @return a bitstream filter with the specified name or NULL if no such | |||||
| * bitstream filter exists. | |||||
| */ | |||||
| const AVBitStreamFilter *av_bsf_get_by_name(const char *name); | |||||
| /** | |||||
| * Iterate over all registered bitstream filters. | |||||
| * | |||||
| * @param opaque a pointer where libavcodec will store the iteration state. Must | |||||
| * point to NULL to start the iteration. | |||||
| * | |||||
| * @return the next registered bitstream filter or NULL when the iteration is | |||||
| * finished | |||||
| */ | |||||
| const AVBitStreamFilter *av_bsf_next(void **opaque); | |||||
| /** | |||||
| * Allocate a context for a given bitstream filter. The caller must fill in the | |||||
| * context parameters as described in the documentation and then call | |||||
| * av_bsf_init() before sending any data to the filter. | |||||
| * | |||||
| * @param filter the filter for which to allocate an instance. | |||||
| * @param ctx a pointer into which the pointer to the newly-allocated context | |||||
| * will be written. It must be freed with av_bsf_free() after the | |||||
| * filtering is done. | |||||
| * | |||||
| * @return 0 on success, a negative AVERROR code on failure | |||||
| */ | |||||
| int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx); | |||||
| /** | |||||
| * Prepare the filter for use, after all the parameters and options have been | |||||
| * set. | |||||
| */ | |||||
| int av_bsf_init(AVBSFContext *ctx); | |||||
| /** | |||||
| * Submit a packet for filtering. | |||||
| * | |||||
| * After sending each packet, the filter must be completely drained by calling | |||||
| * av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or | |||||
| * AVERROR_EOF. | |||||
| * | |||||
| * @param pkt the packet to filter. The bitstream filter will take ownership of | |||||
| * the packet and reset the contents of pkt. pkt is not touched if an error occurs. | |||||
| * This parameter may be NULL, which signals the end of the stream (i.e. no more | |||||
| * packets will be sent). That will cause the filter to output any packets it | |||||
| * may have buffered internally. | |||||
| * | |||||
| * @return 0 on success, a negative AVERROR on error. | |||||
| */ | |||||
| int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt); | |||||
| /** | |||||
| * Retrieve a filtered packet. | |||||
| * | |||||
| * @param[out] pkt this struct will be filled with the contents of the filtered | |||||
| * packet. It is owned by the caller and must be freed using | |||||
| * av_packet_unref() when it is no longer needed. | |||||
| * This parameter should be "clean" (i.e. freshly allocated | |||||
| * with av_packet_alloc() or unreffed with av_packet_unref()) | |||||
| * when this function is called. If this function returns | |||||
| * successfully, the contents of pkt will be completely | |||||
| * overwritten by the returned data. On failure, pkt is not | |||||
| * touched. | |||||
| * | |||||
| * @return 0 on success. AVERROR(EAGAIN) if more packets need to be sent to the | |||||
| * filter (using av_bsf_send_packet()) to get more output. AVERROR_EOF if there | |||||
| * will be no further output from the filter. Another negative AVERROR value if | |||||
| * an error occurs. | |||||
| * | |||||
| * @note one input packet may result in several output packets, so after sending | |||||
| * a packet with av_bsf_send_packet(), this function needs to be called | |||||
| * repeatedly until it stops returning 0. It is also possible for a filter to | |||||
| * output fewer packets than were sent to it, so this function may return | |||||
| * AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call. | |||||
| */ | |||||
| int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt); | |||||
| /** | |||||
| * Free a bitstream filter context and everything associated with it; write NULL | |||||
| * into the supplied pointer. | |||||
| */ | |||||
| void av_bsf_free(AVBSFContext **ctx); | |||||
| /** | |||||
| * Get the AVClass for AVBSFContext. It can be used in combination with | |||||
| * AV_OPT_SEARCH_FAKE_OBJ for examining options. | |||||
| * | |||||
| * @see av_opt_find(). | |||||
| */ | |||||
| const AVClass *av_bsf_get_class(void); | |||||
| /* memory */ | /* memory */ | ||||
| @@ -22,59 +22,75 @@ | |||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "libavutil/atomic.h" | #include "libavutil/atomic.h" | ||||
| #include "libavutil/internal.h" | |||||
| #include "libavutil/mem.h" | #include "libavutil/mem.h" | ||||
| static AVBitStreamFilter *first_bitstream_filter = NULL; | |||||
| #if FF_API_OLD_BSF | |||||
| FF_DISABLE_DEPRECATION_WARNINGS | |||||
| AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) | AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) | ||||
| { | { | ||||
| if (f) | |||||
| return f->next; | |||||
| else | |||||
| return first_bitstream_filter; | |||||
| const AVBitStreamFilter *filter = NULL; | |||||
| void *opaque = NULL; | |||||
| while (filter != f) | |||||
| filter = av_bsf_next(&opaque); | |||||
| return av_bsf_next(&opaque); | |||||
| } | } | ||||
| void av_register_bitstream_filter(AVBitStreamFilter *bsf) | void av_register_bitstream_filter(AVBitStreamFilter *bsf) | ||||
| { | { | ||||
| do { | |||||
| bsf->next = first_bitstream_filter; | |||||
| } while(bsf->next != avpriv_atomic_ptr_cas((void * volatile *)&first_bitstream_filter, bsf->next, bsf)); | |||||
| } | } | ||||
| typedef struct BSFCompatContext { | |||||
| AVBSFContext *ctx; | |||||
| int extradata_updated; | |||||
| } BSFCompatContext; | |||||
| AVBitStreamFilterContext *av_bitstream_filter_init(const char *name) | AVBitStreamFilterContext *av_bitstream_filter_init(const char *name) | ||||
| { | { | ||||
| AVBitStreamFilter *bsf = NULL; | |||||
| while (bsf = av_bitstream_filter_next(bsf)) { | |||||
| if (!strcmp(name, bsf->name)) { | |||||
| AVBitStreamFilterContext *bsfc = | |||||
| av_mallocz(sizeof(AVBitStreamFilterContext)); | |||||
| if (!bsfc) | |||||
| return NULL; | |||||
| bsfc->filter = bsf; | |||||
| bsfc->priv_data = NULL; | |||||
| if (bsf->priv_data_size) { | |||||
| bsfc->priv_data = av_mallocz(bsf->priv_data_size); | |||||
| if (!bsfc->priv_data) { | |||||
| av_freep(&bsfc); | |||||
| return NULL; | |||||
| } | |||||
| } | |||||
| return bsfc; | |||||
| } | |||||
| } | |||||
| AVBitStreamFilterContext *ctx = NULL; | |||||
| BSFCompatContext *priv = NULL; | |||||
| const AVBitStreamFilter *bsf; | |||||
| bsf = av_bsf_get_by_name(name); | |||||
| if (!bsf) | |||||
| return NULL; | |||||
| ctx = av_mallocz(sizeof(*ctx)); | |||||
| if (!ctx) | |||||
| return NULL; | |||||
| priv = av_mallocz(sizeof(*priv)); | |||||
| if (!priv) | |||||
| goto fail; | |||||
| ctx->filter = bsf; | |||||
| ctx->priv_data = priv; | |||||
| return ctx; | |||||
| fail: | |||||
| if (priv) | |||||
| av_bsf_free(&priv->ctx); | |||||
| av_freep(&priv); | |||||
| av_freep(&ctx); | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc) | void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc) | ||||
| { | { | ||||
| BSFCompatContext *priv; | |||||
| if (!bsfc) | if (!bsfc) | ||||
| return; | return; | ||||
| if (bsfc->filter->close) | |||||
| bsfc->filter->close(bsfc); | |||||
| priv = bsfc->priv_data; | |||||
| av_bsf_free(&priv->ctx); | |||||
| av_freep(&bsfc->priv_data); | av_freep(&bsfc->priv_data); | ||||
| av_freep(&bsfc->args); | |||||
| av_parser_close(bsfc->parser); | |||||
| av_free(bsfc); | av_free(bsfc); | ||||
| } | } | ||||
| @@ -83,8 +99,75 @@ int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | uint8_t **poutbuf, int *poutbuf_size, | ||||
| const uint8_t *buf, int buf_size, int keyframe) | const uint8_t *buf, int buf_size, int keyframe) | ||||
| { | { | ||||
| *poutbuf = (uint8_t *)buf; | |||||
| *poutbuf_size = buf_size; | |||||
| return bsfc->filter->filter(bsfc, avctx, args ? args : bsfc->args, | |||||
| poutbuf, poutbuf_size, buf, buf_size, keyframe); | |||||
| BSFCompatContext *priv = bsfc->priv_data; | |||||
| AVPacket pkt = { 0 }; | |||||
| int ret; | |||||
| if (!priv->ctx) { | |||||
| ret = av_bsf_alloc(bsfc->filter, &priv->ctx); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ret = avcodec_parameters_from_context(priv->ctx->par_in, avctx); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| priv->ctx->time_base_in = avctx->time_base; | |||||
| ret = av_bsf_init(priv->ctx); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| } | |||||
| pkt.data = buf; | |||||
| pkt.size = buf_size; | |||||
| ret = av_bsf_send_packet(priv->ctx, &pkt); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| *poutbuf = NULL; | |||||
| *poutbuf_size = 0; | |||||
| ret = av_bsf_receive_packet(priv->ctx, &pkt); | |||||
| if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) | |||||
| return 0; | |||||
| else if (ret < 0) | |||||
| return ret; | |||||
| *poutbuf = av_malloc(pkt.size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!*poutbuf) { | |||||
| av_packet_unref(&pkt); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| *poutbuf_size = pkt.size; | |||||
| memcpy(*poutbuf, pkt.data, pkt.size); | |||||
| av_packet_unref(&pkt); | |||||
| /* drain all the remaining packets we cannot return */ | |||||
| while (ret >= 0) { | |||||
| ret = av_bsf_receive_packet(priv->ctx, &pkt); | |||||
| av_packet_unref(&pkt); | |||||
| } | |||||
| if (!priv->extradata_updated) { | |||||
| /* update extradata in avctx from the output codec parameters */ | |||||
| if (priv->ctx->par_out->extradata_size && (!args || !strstr(args, "private_spspps_buf"))) { | |||||
| av_freep(&avctx->extradata); | |||||
| avctx->extradata_size = 0; | |||||
| avctx->extradata = av_mallocz(priv->ctx->par_out->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!avctx->extradata) | |||||
| return AVERROR(ENOMEM); | |||||
| memcpy(avctx->extradata, priv->ctx->par_out->extradata, priv->ctx->par_out->extradata_size); | |||||
| avctx->extradata_size = priv->ctx->par_out->extradata_size; | |||||
| } | |||||
| priv->extradata_updated = 1; | |||||
| } | |||||
| return 1; | |||||
| } | } | ||||
| FF_ENABLE_DEPRECATION_WARNINGS | |||||
| #endif | |||||
| @@ -0,0 +1,137 @@ | |||||
| /* | |||||
| * 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 "config.h" | |||||
| #include "libavutil/common.h" | |||||
| #include "libavutil/log.h" | |||||
| #include "avcodec.h" | |||||
| #include "bsf.h" | |||||
| extern const AVBitStreamFilter ff_aac_adtstoasc_bsf; | |||||
| extern const AVBitStreamFilter ff_chomp_bsf; | |||||
| extern const AVBitStreamFilter ff_dump_extradata_bsf; | |||||
| extern const AVBitStreamFilter ff_dca_core_bsf; | |||||
| extern const AVBitStreamFilter ff_h264_mp4toannexb_bsf; | |||||
| extern const AVBitStreamFilter ff_hevc_mp4toannexb_bsf; | |||||
| extern const AVBitStreamFilter ff_imx_dump_header_bsf; | |||||
| extern const AVBitStreamFilter ff_mjpeg2jpeg_bsf; | |||||
| extern const AVBitStreamFilter ff_mjpega_dump_header_bsf; | |||||
| extern const AVBitStreamFilter ff_mp3_header_decompress_bsf; | |||||
| extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf; | |||||
| extern const AVBitStreamFilter ff_mov2textsub_bsf; | |||||
| extern const AVBitStreamFilter ff_noise_bsf; | |||||
| extern const AVBitStreamFilter ff_remove_extradata_bsf; | |||||
| extern const AVBitStreamFilter ff_text2movsub_bsf; | |||||
| extern const AVBitStreamFilter ff_vp9_superframe_bsf; | |||||
| static const AVBitStreamFilter *bitstream_filters[] = { | |||||
| #if CONFIG_AAC_ADTSTOASC_BSF | |||||
| &ff_aac_adtstoasc_bsf, | |||||
| #endif | |||||
| #if CONFIG_CHOMP_BSF | |||||
| &ff_chomp_bsf, | |||||
| #endif | |||||
| #if CONFIG_DUMP_EXTRADATA_BSF | |||||
| &ff_dump_extradata_bsf, | |||||
| #endif | |||||
| #if CONFIG_DCA_CORE_BSF | |||||
| &ff_dca_core_bsf, | |||||
| #endif | |||||
| #if CONFIG_H264_MP4TOANNEXB_BSF | |||||
| &ff_h264_mp4toannexb_bsf, | |||||
| #endif | |||||
| #if CONFIG_HEVC_MP4TOANNEXB_BSF | |||||
| &ff_hevc_mp4toannexb_bsf, | |||||
| #endif | |||||
| #if CONFIG_IMX_DUMP_HEADER_BSF | |||||
| &ff_imx_dump_header_bsf, | |||||
| #endif | |||||
| #if CONFIG_MJPEG2JPEG_BSF | |||||
| &ff_mjpeg2jpeg_bsf, | |||||
| #endif | |||||
| #if CONFIG_MJPEGA_DUMP_HEADER_BSF | |||||
| &ff_mjpega_dump_header_bsf, | |||||
| #endif | |||||
| #if CONFIG_MP3_HEADER_DECOMPRESS_BSF | |||||
| &ff_mp3_header_decompress_bsf, | |||||
| #endif | |||||
| #if CONFIG_MPEG4_UNPACK_BFRAMES_BSF | |||||
| &ff_mpeg4_unpack_bframes_bsf, | |||||
| #endif | |||||
| #if CONFIG_MOV2TEXTSUB_BSF | |||||
| &ff_mov2textsub_bsf, | |||||
| #endif | |||||
| #if CONFIG_NOISE_BSF | |||||
| &ff_noise_bsf, | |||||
| #endif | |||||
| #if CONFIG_REMOVE_EXTRADATA_BSF | |||||
| &ff_remove_extradata_bsf, | |||||
| #endif | |||||
| #if CONFIG_TEXT2MOVSUB_BSF | |||||
| &ff_text2movsub_bsf, | |||||
| #endif | |||||
| #if CONFIG_VP9_SUPERFRAME_BSF | |||||
| &ff_vp9_superframe_bsf, | |||||
| #endif | |||||
| NULL, | |||||
| }; | |||||
| const AVBitStreamFilter *av_bsf_next(void **opaque) | |||||
| { | |||||
| uintptr_t i = (uintptr_t)*opaque; | |||||
| const AVBitStreamFilter *f = bitstream_filters[i]; | |||||
| if (f) | |||||
| *opaque = (void*)(i + 1); | |||||
| return f; | |||||
| } | |||||
| const AVBitStreamFilter *av_bsf_get_by_name(const char *name) | |||||
| { | |||||
| int i; | |||||
| for (i = 0; bitstream_filters[i]; i++) { | |||||
| const AVBitStreamFilter *f = bitstream_filters[i]; | |||||
| if (!strcmp(f->name, name)) | |||||
| return f; | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| const AVClass *ff_bsf_child_class_next(const AVClass *prev) | |||||
| { | |||||
| int i; | |||||
| /* find the filter that corresponds to prev */ | |||||
| for (i = 0; prev && bitstream_filters[i]; i++) { | |||||
| if (bitstream_filters[i]->priv_class == prev) { | |||||
| i++; | |||||
| break; | |||||
| } | |||||
| } | |||||
| /* find next filter with priv options */ | |||||
| for (; bitstream_filters[i]; i++) | |||||
| if (bitstream_filters[i]->priv_class) | |||||
| return bitstream_filters[i]->priv_class; | |||||
| return NULL; | |||||
| } | |||||
| @@ -0,0 +1,219 @@ | |||||
| /* | |||||
| * 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 <string.h> | |||||
| #include "libavutil/log.h" | |||||
| #include "libavutil/mem.h" | |||||
| #include "libavutil/opt.h" | |||||
| #include "avcodec.h" | |||||
| #include "bsf.h" | |||||
| struct AVBSFInternal { | |||||
| AVPacket *buffer_pkt; | |||||
| int eof; | |||||
| }; | |||||
| void av_bsf_free(AVBSFContext **pctx) | |||||
| { | |||||
| AVBSFContext *ctx; | |||||
| if (!pctx || !*pctx) | |||||
| return; | |||||
| ctx = *pctx; | |||||
| if (ctx->filter->close) | |||||
| ctx->filter->close(ctx); | |||||
| if (ctx->filter->priv_class && ctx->priv_data) | |||||
| av_opt_free(ctx->priv_data); | |||||
| av_opt_free(ctx); | |||||
| av_packet_free(&ctx->internal->buffer_pkt); | |||||
| av_freep(&ctx->internal); | |||||
| av_freep(&ctx->priv_data); | |||||
| avcodec_parameters_free(&ctx->par_in); | |||||
| avcodec_parameters_free(&ctx->par_out); | |||||
| av_freep(pctx); | |||||
| } | |||||
| static void *bsf_child_next(void *obj, void *prev) | |||||
| { | |||||
| AVBSFContext *ctx = obj; | |||||
| if (!prev && ctx->filter->priv_class) | |||||
| return ctx->priv_data; | |||||
| return NULL; | |||||
| } | |||||
| static const AVClass bsf_class = { | |||||
| .class_name = "AVBSFContext", | |||||
| .item_name = av_default_item_name, | |||||
| .version = LIBAVUTIL_VERSION_INT, | |||||
| .child_next = bsf_child_next, | |||||
| .child_class_next = ff_bsf_child_class_next, | |||||
| }; | |||||
| const AVClass *av_bsf_get_class(void) | |||||
| { | |||||
| return &bsf_class; | |||||
| } | |||||
| int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **pctx) | |||||
| { | |||||
| AVBSFContext *ctx; | |||||
| int ret; | |||||
| ctx = av_mallocz(sizeof(*ctx)); | |||||
| if (!ctx) | |||||
| return AVERROR(ENOMEM); | |||||
| ctx->av_class = &bsf_class; | |||||
| ctx->filter = filter; | |||||
| ctx->par_in = avcodec_parameters_alloc(); | |||||
| ctx->par_out = avcodec_parameters_alloc(); | |||||
| if (!ctx->par_in || !ctx->par_out) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| ctx->internal = av_mallocz(sizeof(*ctx->internal)); | |||||
| if (!ctx->internal) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| ctx->internal->buffer_pkt = av_packet_alloc(); | |||||
| if (!ctx->internal->buffer_pkt) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| av_opt_set_defaults(ctx); | |||||
| /* allocate priv data and init private options */ | |||||
| if (filter->priv_data_size) { | |||||
| ctx->priv_data = av_mallocz(filter->priv_data_size); | |||||
| if (!ctx->priv_data) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| if (filter->priv_class) { | |||||
| *(const AVClass **)ctx->priv_data = filter->priv_class; | |||||
| av_opt_set_defaults(ctx->priv_data); | |||||
| } | |||||
| } | |||||
| *pctx = ctx; | |||||
| return 0; | |||||
| fail: | |||||
| av_bsf_free(&ctx); | |||||
| return ret; | |||||
| } | |||||
| int av_bsf_init(AVBSFContext *ctx) | |||||
| { | |||||
| int ret, i; | |||||
| /* check that the codec is supported */ | |||||
| if (ctx->filter->codec_ids) { | |||||
| for (i = 0; ctx->filter->codec_ids[i] != AV_CODEC_ID_NONE; i++) | |||||
| if (ctx->par_in->codec_id == ctx->filter->codec_ids[i]) | |||||
| break; | |||||
| if (ctx->filter->codec_ids[i] == AV_CODEC_ID_NONE) { | |||||
| const AVCodecDescriptor *desc = avcodec_descriptor_get(ctx->par_in->codec_id); | |||||
| av_log(ctx, AV_LOG_ERROR, "Codec '%s' (%d) is not supported by the " | |||||
| "bitstream filter '%s'. Supported codecs are: ", | |||||
| desc ? desc->name : "unknown", ctx->par_in->codec_id, ctx->filter->name); | |||||
| for (i = 0; ctx->filter->codec_ids[i] != AV_CODEC_ID_NONE; i++) { | |||||
| desc = avcodec_descriptor_get(ctx->filter->codec_ids[i]); | |||||
| av_log(ctx, AV_LOG_ERROR, "%s (%d) ", | |||||
| desc ? desc->name : "unknown", ctx->filter->codec_ids[i]); | |||||
| } | |||||
| av_log(ctx, AV_LOG_ERROR, "\n"); | |||||
| return AVERROR(EINVAL); | |||||
| } | |||||
| } | |||||
| /* initialize output parameters to be the same as input | |||||
| * init below might overwrite that */ | |||||
| ret = avcodec_parameters_copy(ctx->par_out, ctx->par_in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ctx->time_base_out = ctx->time_base_in; | |||||
| if (ctx->filter->init) { | |||||
| ret = ctx->filter->init(ctx); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt) | |||||
| { | |||||
| if (!pkt || !pkt->data) { | |||||
| ctx->internal->eof = 1; | |||||
| return 0; | |||||
| } | |||||
| if (ctx->internal->eof) { | |||||
| av_log(ctx, AV_LOG_ERROR, "A non-NULL packet sent after an EOF.\n"); | |||||
| return AVERROR(EINVAL); | |||||
| } | |||||
| if (ctx->internal->buffer_pkt->data || | |||||
| ctx->internal->buffer_pkt->side_data_elems) | |||||
| return AVERROR(EAGAIN); | |||||
| av_packet_move_ref(ctx->internal->buffer_pkt, pkt); | |||||
| return 0; | |||||
| } | |||||
| int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt) | |||||
| { | |||||
| return ctx->filter->filter(ctx, pkt); | |||||
| } | |||||
| int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt) | |||||
| { | |||||
| AVBSFInternal *in = ctx->internal; | |||||
| AVPacket *tmp_pkt; | |||||
| if (in->eof) | |||||
| return AVERROR_EOF; | |||||
| if (!ctx->internal->buffer_pkt->data && | |||||
| !ctx->internal->buffer_pkt->side_data_elems) | |||||
| return AVERROR(EAGAIN); | |||||
| tmp_pkt = av_packet_alloc(); | |||||
| if (!tmp_pkt) | |||||
| return AVERROR(ENOMEM); | |||||
| *pkt = ctx->internal->buffer_pkt; | |||||
| ctx->internal->buffer_pkt = tmp_pkt; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,33 @@ | |||||
| /* | |||||
| * 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 AVCODEC_BSF_H | |||||
| #define AVCODEC_BSF_H | |||||
| #include "avcodec.h" | |||||
| /** | |||||
| * Called by the biststream filters to get the next packet for filtering. | |||||
| * The filter is responsible for either freeing the packet or passing it to the | |||||
| * caller. | |||||
| */ | |||||
| int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt); | |||||
| const AVClass *ff_bsf_child_class_next(const AVClass *prev); | |||||
| #endif /* AVCODEC_BSF_H */ | |||||
| @@ -20,19 +20,23 @@ | |||||
| */ | */ | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "internal.h" | #include "internal.h" | ||||
| static int chomp_filter(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int chomp_filter(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| while (buf_size > 0 && !buf[buf_size-1]) | |||||
| buf_size--; | |||||
| AVPacket *in; | |||||
| int ret; | |||||
| *poutbuf = (uint8_t*) buf; | |||||
| *poutbuf_size = buf_size; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| while (in->size > 0 && !in->data[in->size - 1]) | |||||
| in->size--; | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -40,7 +44,7 @@ static int chomp_filter(AVBitStreamFilterContext *bsfc, | |||||
| /** | /** | ||||
| * This filter removes a string of NULL bytes from the end of a packet. | * This filter removes a string of NULL bytes from the end of a packet. | ||||
| */ | */ | ||||
| AVBitStreamFilter ff_chomp_bsf = { | |||||
| const AVBitStreamFilter ff_chomp_bsf = { | |||||
| .name = "chomp", | .name = "chomp", | ||||
| .filter = chomp_filter, | .filter = chomp_filter, | ||||
| }; | }; | ||||
| @@ -19,21 +19,23 @@ | |||||
| */ | */ | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "bytestream.h" | #include "bytestream.h" | ||||
| #include "dca_syncwords.h" | #include "dca_syncwords.h" | ||||
| #include "libavutil/mem.h" | #include "libavutil/mem.h" | ||||
| static int dca_core(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int dca_core_filter(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| AVPacket *in; | |||||
| GetByteContext gb; | GetByteContext gb; | ||||
| uint32_t syncword; | uint32_t syncword; | ||||
| int core_size = 0; | |||||
| int core_size = 0, ret; | |||||
| bytestream2_init(&gb, buf, buf_size); | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| bytestream2_init(&gb, in->data, in->size); | |||||
| syncword = bytestream2_get_be32(&gb); | syncword = bytestream2_get_be32(&gb); | ||||
| bytestream2_skip(&gb, 1); | bytestream2_skip(&gb, 1); | ||||
| @@ -43,18 +45,22 @@ static int dca_core(AVBitStreamFilterContext *bsfc, | |||||
| break; | break; | ||||
| } | } | ||||
| *poutbuf = (uint8_t *)buf; | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| if (core_size > 0 && core_size <= buf_size) { | |||||
| *poutbuf_size = core_size; | |||||
| } else { | |||||
| *poutbuf_size = buf_size; | |||||
| if (core_size > 0 && core_size <= out->size) { | |||||
| out->size = core_size; | |||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| AVBitStreamFilter ff_dca_core_bsf = { | |||||
| .name = "dca_core", | |||||
| .filter = dca_core, | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_DTS, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_dca_core_bsf = { | |||||
| .name = "dca_core", | |||||
| .filter = dca_core_filter, | |||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -21,34 +21,81 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "libavutil/log.h" | |||||
| #include "libavutil/mem.h" | #include "libavutil/mem.h" | ||||
| #include "libavutil/opt.h" | |||||
| enum DumpFreq { | |||||
| DUMP_FREQ_KEYFRAME, | |||||
| DUMP_FREQ_ALL, | |||||
| }; | |||||
| typedef struct DumpExtradataContext { | |||||
| const AVClass *class; | |||||
| int freq; | |||||
| } DumpExtradataContext; | |||||
| static int dump_extradata(AVBSFContext *ctx, AVPacket *out) | |||||
| { | |||||
| DumpExtradataContext *s = ctx->priv_data; | |||||
| AVPacket *in; | |||||
| int ret = 0; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| if (ctx->par_in->extradata && | |||||
| (s->freq == DUMP_FREQ_ALL || | |||||
| (s->freq == DUMP_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY))) { | |||||
| if (in->size >= INT_MAX - ctx->par_in->extradata_size) { | |||||
| ret = AVERROR(ERANGE); | |||||
| goto fail; | |||||
| } | |||||
| ret = av_new_packet(out, in->size + ctx->par_in->extradata_size); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| static int dump_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe){ | |||||
| int cmd= args ? *args : 0; | |||||
| /* cast to avoid warning about discarding qualifiers */ | |||||
| if(avctx->extradata){ | |||||
| if( (keyframe && (avctx->flags2 & AV_CODEC_FLAG2_LOCAL_HEADER) && cmd == 'a') | |||||
| ||(keyframe && (cmd=='k' || !cmd)) | |||||
| ||(cmd=='e') | |||||
| /*||(? && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_BEGIN)*/){ | |||||
| int size= buf_size + avctx->extradata_size; | |||||
| *poutbuf_size= size; | |||||
| *poutbuf= av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!*poutbuf) | |||||
| return AVERROR(ENOMEM); | |||||
| memcpy(*poutbuf, avctx->extradata, avctx->extradata_size); | |||||
| memcpy((*poutbuf) + avctx->extradata_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| return 1; | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) { | |||||
| av_packet_unref(out); | |||||
| goto fail; | |||||
| } | } | ||||
| memcpy(out->data, ctx->par_in->extradata, ctx->par_in->extradata_size); | |||||
| memcpy(out->data + ctx->par_in->extradata_size, in->data, in->size); | |||||
| } else { | |||||
| av_packet_move_ref(out, in); | |||||
| } | } | ||||
| return 0; | |||||
| fail: | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_dump_extradata_bsf={ | |||||
| .name = "dump_extra", | |||||
| .filter = dump_extradata, | |||||
| #define OFFSET(x) offsetof(DumpExtradataContext, x) | |||||
| static const AVOption options[] = { | |||||
| { "freq", "When do dump extradata", OFFSET(freq), AV_OPT_TYPE_INT, | |||||
| { .i64 = DUMP_FREQ_KEYFRAME }, DUMP_FREQ_KEYFRAME, DUMP_FREQ_ALL, 0, "freq" }, | |||||
| { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .unit = "freq" }, | |||||
| { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_ALL }, .unit = "freq" }, | |||||
| { NULL }, | |||||
| }; | |||||
| static const AVClass dump_extradata_class = { | |||||
| .class_name = "dump_extradata bsf", | |||||
| .item_name = av_default_item_name, | |||||
| .option = options, | |||||
| .version = LIBAVUTIL_VERSION_MAJOR, | |||||
| }; | |||||
| const AVBitStreamFilter ff_dump_extradata_bsf = { | |||||
| .name = "dump_extra", | |||||
| .priv_data_size = sizeof(DumpExtradataContext), | |||||
| .priv_class = &dump_extradata_class, | |||||
| .filter = dump_extradata, | |||||
| }; | }; | ||||
| @@ -23,7 +23,9 @@ | |||||
| #include "libavutil/intreadwrite.h" | #include "libavutil/intreadwrite.h" | ||||
| #include "libavutil/mem.h" | #include "libavutil/mem.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| typedef struct H264BSFContext { | typedef struct H264BSFContext { | ||||
| int32_t sps_offset; | int32_t sps_offset; | ||||
| @@ -33,66 +35,53 @@ typedef struct H264BSFContext { | |||||
| uint8_t idr_sps_seen; | uint8_t idr_sps_seen; | ||||
| uint8_t idr_pps_seen; | uint8_t idr_pps_seen; | ||||
| int extradata_parsed; | int extradata_parsed; | ||||
| /* When private_spspps is zero then spspps_buf points to global extradata | |||||
| and bsf does replace a global extradata to own-allocated version (default | |||||
| behaviour). | |||||
| When private_spspps is non-zero the bsf uses a private version of spspps buf. | |||||
| This mode necessary when bsf uses in decoder, else bsf has issues after | |||||
| decoder re-initialization. Use the "private_spspps_buf" argument to | |||||
| activate this mode. | |||||
| */ | |||||
| int private_spspps; | |||||
| uint8_t *spspps_buf; | |||||
| uint32_t spspps_size; | |||||
| } H264BSFContext; | } H264BSFContext; | ||||
| static int alloc_and_copy(uint8_t **poutbuf, int *poutbuf_size, | |||||
| static int alloc_and_copy(AVPacket *out, | |||||
| const uint8_t *sps_pps, uint32_t sps_pps_size, | const uint8_t *sps_pps, uint32_t sps_pps_size, | ||||
| const uint8_t *in, uint32_t in_size) | const uint8_t *in, uint32_t in_size) | ||||
| { | { | ||||
| uint32_t offset = *poutbuf_size; | |||||
| uint32_t offset = out->size; | |||||
| uint8_t nal_header_size = offset ? 3 : 4; | uint8_t nal_header_size = offset ? 3 : 4; | ||||
| int err; | int err; | ||||
| *poutbuf_size += sps_pps_size + in_size + nal_header_size; | |||||
| if ((err = av_reallocp(poutbuf, | |||||
| *poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { | |||||
| *poutbuf_size = 0; | |||||
| err = av_grow_packet(out, sps_pps_size + in_size + nal_header_size); | |||||
| if (err < 0) | |||||
| return err; | return err; | ||||
| } | |||||
| if (sps_pps) | if (sps_pps) | ||||
| memcpy(*poutbuf + offset, sps_pps, sps_pps_size); | |||||
| memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size); | |||||
| memcpy(out->data + offset, sps_pps, sps_pps_size); | |||||
| memcpy(out->data + sps_pps_size + nal_header_size + offset, in, in_size); | |||||
| if (!offset) { | if (!offset) { | ||||
| AV_WB32(*poutbuf + sps_pps_size, 1); | |||||
| AV_WB32(out->data + sps_pps_size, 1); | |||||
| } else { | } else { | ||||
| (*poutbuf + offset + sps_pps_size)[0] = | |||||
| (*poutbuf + offset + sps_pps_size)[1] = 0; | |||||
| (*poutbuf + offset + sps_pps_size)[2] = 1; | |||||
| (out->data + offset + sps_pps_size)[0] = | |||||
| (out->data + offset + sps_pps_size)[1] = 0; | |||||
| (out->data + offset + sps_pps_size)[2] = 1; | |||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int h264_extradata_to_annexb(H264BSFContext *ctx, AVCodecContext *avctx, const int padding) | |||||
| static int h264_extradata_to_annexb(AVBSFContext *ctx, const int padding) | |||||
| { | { | ||||
| H264BSFContext *s = ctx->priv_data; | |||||
| uint16_t unit_size; | uint16_t unit_size; | ||||
| uint64_t total_size = 0; | uint64_t total_size = 0; | ||||
| uint8_t *out = NULL, unit_nb, sps_done = 0, | uint8_t *out = NULL, unit_nb, sps_done = 0, | ||||
| sps_seen = 0, pps_seen = 0; | sps_seen = 0, pps_seen = 0; | ||||
| const uint8_t *extradata = avctx->extradata + 4; | |||||
| const uint8_t *extradata = ctx->par_in->extradata + 4; | |||||
| static const uint8_t nalu_header[4] = { 0, 0, 0, 1 }; | static const uint8_t nalu_header[4] = { 0, 0, 0, 1 }; | ||||
| int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size | int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size | ||||
| ctx->sps_offset = ctx->pps_offset = -1; | |||||
| s->sps_offset = s->pps_offset = -1; | |||||
| /* retrieve sps and pps unit(s) */ | /* retrieve sps and pps unit(s) */ | ||||
| unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */ | unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */ | ||||
| if (!unit_nb) { | if (!unit_nb) { | ||||
| goto pps; | goto pps; | ||||
| } else { | } else { | ||||
| ctx->sps_offset = 0; | |||||
| s->sps_offset = 0; | |||||
| sps_seen = 1; | sps_seen = 1; | ||||
| } | } | ||||
| @@ -102,13 +91,13 @@ static int h264_extradata_to_annexb(H264BSFContext *ctx, AVCodecContext *avctx, | |||||
| unit_size = AV_RB16(extradata); | unit_size = AV_RB16(extradata); | ||||
| total_size += unit_size + 4; | total_size += unit_size + 4; | ||||
| if (total_size > INT_MAX - padding) { | if (total_size > INT_MAX - padding) { | ||||
| av_log(avctx, AV_LOG_ERROR, | |||||
| av_log(ctx, AV_LOG_ERROR, | |||||
| "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n"); | "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n"); | ||||
| av_free(out); | av_free(out); | ||||
| return AVERROR(EINVAL); | return AVERROR(EINVAL); | ||||
| } | } | ||||
| if (extradata + 2 + unit_size > avctx->extradata + avctx->extradata_size) { | |||||
| av_log(avctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, " | |||||
| if (extradata + 2 + unit_size > ctx->par_in->extradata + ctx->par_in->extradata_size) { | |||||
| av_log(ctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, " | |||||
| "corrupted stream or invalid MP4/AVCC bitstream\n"); | "corrupted stream or invalid MP4/AVCC bitstream\n"); | ||||
| av_free(out); | av_free(out); | ||||
| return AVERROR(EINVAL); | return AVERROR(EINVAL); | ||||
| @@ -122,7 +111,7 @@ pps: | |||||
| if (!unit_nb && !sps_done++) { | if (!unit_nb && !sps_done++) { | ||||
| unit_nb = *extradata++; /* number of pps unit(s) */ | unit_nb = *extradata++; /* number of pps unit(s) */ | ||||
| if (unit_nb) { | if (unit_nb) { | ||||
| ctx->pps_offset = total_size; | |||||
| s->pps_offset = total_size; | |||||
| pps_seen = 1; | pps_seen = 1; | ||||
| } | } | ||||
| } | } | ||||
| @@ -132,93 +121,100 @@ pps: | |||||
| memset(out + total_size, 0, padding); | memset(out + total_size, 0, padding); | ||||
| if (!sps_seen) | if (!sps_seen) | ||||
| av_log(avctx, AV_LOG_WARNING, | |||||
| av_log(ctx, AV_LOG_WARNING, | |||||
| "Warning: SPS NALU missing or invalid. " | "Warning: SPS NALU missing or invalid. " | ||||
| "The resulting stream may not play.\n"); | "The resulting stream may not play.\n"); | ||||
| if (!pps_seen) | if (!pps_seen) | ||||
| av_log(avctx, AV_LOG_WARNING, | |||||
| av_log(ctx, AV_LOG_WARNING, | |||||
| "Warning: PPS NALU missing or invalid. " | "Warning: PPS NALU missing or invalid. " | ||||
| "The resulting stream may not play.\n"); | "The resulting stream may not play.\n"); | ||||
| if (!ctx->private_spspps) { | |||||
| av_free(avctx->extradata); | |||||
| avctx->extradata = out; | |||||
| avctx->extradata_size = total_size; | |||||
| } | |||||
| ctx->spspps_buf = out; | |||||
| ctx->spspps_size = total_size; | |||||
| av_freep(&ctx->par_out->extradata); | |||||
| ctx->par_out->extradata = out; | |||||
| ctx->par_out->extradata_size = total_size; | |||||
| return length_size; | return length_size; | ||||
| } | } | ||||
| static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int h264_mp4toannexb_init(AVBSFContext *ctx) | |||||
| { | { | ||||
| H264BSFContext *ctx = bsfc->priv_data; | |||||
| int i; | |||||
| H264BSFContext *s = ctx->priv_data; | |||||
| int ret; | |||||
| /* retrieve sps and pps NAL units from extradata */ | |||||
| if (ctx->par_in->extradata_size >= 6) { | |||||
| ret = h264_extradata_to_annexb(ctx, AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| s->length_size = ret; | |||||
| s->new_idr = 1; | |||||
| s->idr_sps_seen = 0; | |||||
| s->idr_pps_seen = 0; | |||||
| s->extradata_parsed = 1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) | |||||
| { | |||||
| H264BSFContext *s = ctx->priv_data; | |||||
| AVPacket *in; | |||||
| uint8_t unit_type; | uint8_t unit_type; | ||||
| int32_t nal_size; | int32_t nal_size; | ||||
| uint32_t cumul_size = 0; | uint32_t cumul_size = 0; | ||||
| const uint8_t *buf_end = buf + buf_size; | |||||
| int ret = 0; | |||||
| const uint8_t *buf; | |||||
| const uint8_t *buf_end; | |||||
| int buf_size; | |||||
| int ret = 0, i; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| /* nothing to filter */ | /* nothing to filter */ | ||||
| if (!avctx->extradata || avctx->extradata_size < 6) { | |||||
| *poutbuf = (uint8_t *)buf; | |||||
| *poutbuf_size = buf_size; | |||||
| if (!s->extradata_parsed) { | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* retrieve sps and pps NAL units from extradata */ | |||||
| if (!ctx->extradata_parsed) { | |||||
| if (args && strstr(args, "private_spspps_buf")) | |||||
| ctx->private_spspps = 1; | |||||
| buf = in->data; | |||||
| buf_size = in->size; | |||||
| buf_end = in->data + in->size; | |||||
| ret = h264_extradata_to_annexb(ctx, avctx, AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ctx->length_size = ret; | |||||
| ctx->new_idr = 1; | |||||
| ctx->idr_sps_seen = 0; | |||||
| ctx->idr_pps_seen = 0; | |||||
| ctx->extradata_parsed = 1; | |||||
| } | |||||
| *poutbuf_size = 0; | |||||
| *poutbuf = NULL; | |||||
| do { | do { | ||||
| ret= AVERROR(EINVAL); | ret= AVERROR(EINVAL); | ||||
| if (buf + ctx->length_size > buf_end) | |||||
| if (buf + s->length_size > buf_end) | |||||
| goto fail; | goto fail; | ||||
| for (nal_size = 0, i = 0; i<ctx->length_size; i++) | |||||
| for (nal_size = 0, i = 0; i<s->length_size; i++) | |||||
| nal_size = (nal_size << 8) | buf[i]; | nal_size = (nal_size << 8) | buf[i]; | ||||
| buf += ctx->length_size; | |||||
| buf += s->length_size; | |||||
| unit_type = *buf & 0x1f; | unit_type = *buf & 0x1f; | ||||
| if (nal_size > buf_end - buf || nal_size < 0) | if (nal_size > buf_end - buf || nal_size < 0) | ||||
| goto fail; | goto fail; | ||||
| if (unit_type == 7) | if (unit_type == 7) | ||||
| ctx->idr_sps_seen = ctx->new_idr = 1; | |||||
| s->idr_sps_seen = s->new_idr = 1; | |||||
| else if (unit_type == 8) { | else if (unit_type == 8) { | ||||
| ctx->idr_pps_seen = ctx->new_idr = 1; | |||||
| s->idr_pps_seen = s->new_idr = 1; | |||||
| /* if SPS has not been seen yet, prepend the AVCC one to PPS */ | /* if SPS has not been seen yet, prepend the AVCC one to PPS */ | ||||
| if (!ctx->idr_sps_seen) { | |||||
| if (ctx->sps_offset == -1) | |||||
| av_log(avctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n"); | |||||
| if (!s->idr_sps_seen) { | |||||
| if (s->sps_offset == -1) | |||||
| av_log(ctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n"); | |||||
| else { | else { | ||||
| if ((ret = alloc_and_copy(poutbuf, poutbuf_size, | |||||
| ctx->spspps_buf + ctx->sps_offset, | |||||
| ctx->pps_offset != -1 ? ctx->pps_offset : ctx->spspps_size - ctx->sps_offset, | |||||
| if ((ret = alloc_and_copy(out, | |||||
| ctx->par_out->extradata + s->sps_offset, | |||||
| s->pps_offset != -1 ? s->pps_offset : ctx->par_out->extradata_size - s->sps_offset, | |||||
| buf, nal_size)) < 0) | buf, nal_size)) < 0) | ||||
| goto fail; | goto fail; | ||||
| ctx->idr_sps_seen = 1; | |||||
| s->idr_sps_seen = 1; | |||||
| goto next_nal; | goto next_nal; | ||||
| } | } | ||||
| } | } | ||||
| @@ -227,61 +223,61 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, | |||||
| /* if this is a new IDR picture following an IDR picture, reset the idr flag. | /* if this is a new IDR picture following an IDR picture, reset the idr flag. | ||||
| * Just check first_mb_in_slice to be 0 as this is the simplest solution. | * Just check first_mb_in_slice to be 0 as this is the simplest solution. | ||||
| * This could be checking idr_pic_id instead, but would complexify the parsing. */ | * This could be checking idr_pic_id instead, but would complexify the parsing. */ | ||||
| if (!ctx->new_idr && unit_type == 5 && (buf[1] & 0x80)) | |||||
| ctx->new_idr = 1; | |||||
| if (!s->new_idr && unit_type == 5 && (buf[1] & 0x80)) | |||||
| s->new_idr = 1; | |||||
| /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ | /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ | ||||
| if (ctx->new_idr && unit_type == 5 && !ctx->idr_sps_seen && !ctx->idr_pps_seen) { | |||||
| if ((ret=alloc_and_copy(poutbuf, poutbuf_size, | |||||
| ctx->spspps_buf, ctx->spspps_size, | |||||
| if (s->new_idr && unit_type == 5 && !s->idr_sps_seen && !s->idr_pps_seen) { | |||||
| if ((ret=alloc_and_copy(out, | |||||
| ctx->par_out->extradata, ctx->par_out->extradata_size, | |||||
| buf, nal_size)) < 0) | buf, nal_size)) < 0) | ||||
| goto fail; | goto fail; | ||||
| ctx->new_idr = 0; | |||||
| s->new_idr = 0; | |||||
| /* if only SPS has been seen, also insert PPS */ | /* if only SPS has been seen, also insert PPS */ | ||||
| } else if (ctx->new_idr && unit_type == 5 && ctx->idr_sps_seen && !ctx->idr_pps_seen) { | |||||
| if (ctx->pps_offset == -1) { | |||||
| av_log(avctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); | |||||
| if ((ret = alloc_and_copy(poutbuf, poutbuf_size, | |||||
| NULL, 0, buf, nal_size)) < 0) | |||||
| } else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) { | |||||
| if (s->pps_offset == -1) { | |||||
| av_log(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); | |||||
| if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) | |||||
| goto fail; | goto fail; | ||||
| } else if ((ret = alloc_and_copy(poutbuf, poutbuf_size, | |||||
| ctx->spspps_buf + ctx->pps_offset, ctx->spspps_size - ctx->pps_offset, | |||||
| } else if ((ret = alloc_and_copy(out, | |||||
| ctx->par_out->extradata + s->pps_offset, ctx->par_out->extradata_size - s->pps_offset, | |||||
| buf, nal_size)) < 0) | buf, nal_size)) < 0) | ||||
| goto fail; | goto fail; | ||||
| } else { | } else { | ||||
| if ((ret=alloc_and_copy(poutbuf, poutbuf_size, | |||||
| NULL, 0, buf, nal_size)) < 0) | |||||
| if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) | |||||
| goto fail; | goto fail; | ||||
| if (!ctx->new_idr && unit_type == 1) { | |||||
| ctx->new_idr = 1; | |||||
| ctx->idr_sps_seen = 0; | |||||
| ctx->idr_pps_seen = 0; | |||||
| if (!s->new_idr && unit_type == 1) { | |||||
| s->new_idr = 1; | |||||
| s->idr_sps_seen = 0; | |||||
| s->idr_pps_seen = 0; | |||||
| } | } | ||||
| } | } | ||||
| next_nal: | next_nal: | ||||
| buf += nal_size; | buf += nal_size; | ||||
| cumul_size += nal_size + ctx->length_size; | |||||
| cumul_size += nal_size + s->length_size; | |||||
| } while (cumul_size < buf_size); | } while (cumul_size < buf_size); | ||||
| return 1; | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| fail: | fail: | ||||
| av_freep(poutbuf); | |||||
| *poutbuf_size = 0; | |||||
| if (ret < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| static void h264_mp4toannexb_filter_close(AVBitStreamFilterContext *bsfc) | |||||
| { | |||||
| H264BSFContext *ctx = bsfc->priv_data; | |||||
| if (ctx->private_spspps) | |||||
| av_freep(&ctx->spspps_buf); | |||||
| } | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_H264, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| AVBitStreamFilter ff_h264_mp4toannexb_bsf = { | |||||
| const AVBitStreamFilter ff_h264_mp4toannexb_bsf = { | |||||
| .name = "h264_mp4toannexb", | .name = "h264_mp4toannexb", | ||||
| .priv_data_size = sizeof(H264BSFContext), | .priv_data_size = sizeof(H264BSFContext), | ||||
| .init = h264_mp4toannexb_init, | |||||
| .filter = h264_mp4toannexb_filter, | .filter = h264_mp4toannexb_filter, | ||||
| .close = h264_mp4toannexb_filter_close, | |||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -25,6 +25,7 @@ | |||||
| #include "libavutil/mem.h" | #include "libavutil/mem.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "bytestream.h" | #include "bytestream.h" | ||||
| #include "hevc.h" | #include "hevc.h" | ||||
| @@ -33,23 +34,9 @@ | |||||
| typedef struct HEVCBSFContext { | typedef struct HEVCBSFContext { | ||||
| uint8_t length_size; | uint8_t length_size; | ||||
| int extradata_parsed; | int extradata_parsed; | ||||
| int logged_nonmp4_warning; | |||||
| /* When private_spspps is zero then spspps_buf points to global extradata | |||||
| and bsf does replace a global extradata to own-allocated version (default | |||||
| behaviour). | |||||
| When private_spspps is non-zero the bsf uses a private version of spspps buf. | |||||
| This mode necessary when bsf uses in decoder, else bsf has issues after | |||||
| decoder re-initialization. Use the "private_spspps_buf" argument to | |||||
| activate this mode. | |||||
| */ | |||||
| int private_spspps; | |||||
| uint8_t *spspps_buf; | |||||
| uint32_t spspps_size; | |||||
| } HEVCBSFContext; | } HEVCBSFContext; | ||||
| static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, AVCodecContext *avctx) | |||||
| static int hevc_extradata_to_annexb(AVBSFContext *ctx) | |||||
| { | { | ||||
| GetByteContext gb; | GetByteContext gb; | ||||
| int length_size, num_arrays, i, j; | int length_size, num_arrays, i, j; | ||||
| @@ -58,7 +45,7 @@ static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, AVCodecContext *avctx) | |||||
| uint8_t *new_extradata = NULL; | uint8_t *new_extradata = NULL; | ||||
| size_t new_extradata_size = 0; | size_t new_extradata_size = 0; | ||||
| bytestream2_init(&gb, avctx->extradata, avctx->extradata_size); | |||||
| bytestream2_init(&gb, ctx->par_in->extradata, ctx->par_in->extradata_size); | |||||
| bytestream2_skip(&gb, 21); | bytestream2_skip(&gb, 21); | ||||
| length_size = (bytestream2_get_byte(&gb) & 3) + 1; | length_size = (bytestream2_get_byte(&gb) & 3) + 1; | ||||
| @@ -70,7 +57,7 @@ static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, AVCodecContext *avctx) | |||||
| if (!(type == NAL_VPS || type == NAL_SPS || type == NAL_PPS || | if (!(type == NAL_VPS || type == NAL_SPS || type == NAL_PPS || | ||||
| type == NAL_SEI_PREFIX || type == NAL_SEI_SUFFIX)) { | type == NAL_SEI_PREFIX || type == NAL_SEI_SUFFIX)) { | ||||
| av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit type in extradata: %d\n", | |||||
| av_log(ctx, AV_LOG_ERROR, "Invalid NAL unit type in extradata: %d\n", | |||||
| type); | type); | ||||
| ret = AVERROR_INVALIDDATA; | ret = AVERROR_INVALIDDATA; | ||||
| goto fail; | goto fail; | ||||
| @@ -94,16 +81,12 @@ static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, AVCodecContext *avctx) | |||||
| } | } | ||||
| } | } | ||||
| if (!ctx->private_spspps) { | |||||
| av_freep(&avctx->extradata); | |||||
| avctx->extradata = new_extradata; | |||||
| avctx->extradata_size = new_extradata_size; | |||||
| } | |||||
| ctx->spspps_buf = new_extradata; | |||||
| ctx->spspps_size = new_extradata_size; | |||||
| av_freep(&ctx->par_out->extradata); | |||||
| ctx->par_out->extradata = new_extradata; | |||||
| ctx->par_out->extradata_size = new_extradata_size; | |||||
| if (!new_extradata_size) | if (!new_extradata_size) | ||||
| av_log(avctx, AV_LOG_WARNING, "No parameter sets in the extradata\n"); | |||||
| av_log(ctx, AV_LOG_WARNING, "No parameter sets in the extradata\n"); | |||||
| return length_size; | return length_size; | ||||
| fail: | fail: | ||||
| @@ -111,54 +94,54 @@ fail: | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| static int hevc_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int hevc_mp4toannexb_init(AVBSFContext *ctx) | |||||
| { | |||||
| HEVCBSFContext *s = ctx->priv_data; | |||||
| int ret; | |||||
| if (ctx->par_in->extradata_size < MIN_HEVCC_LENGTH || | |||||
| AV_RB24(ctx->par_in->extradata) == 1 || | |||||
| AV_RB32(ctx->par_in->extradata) == 1) { | |||||
| av_log(ctx, AV_LOG_VERBOSE, | |||||
| "The input looks like it is Annex B already\n"); | |||||
| } else { | |||||
| ret = hevc_extradata_to_annexb(ctx); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| s->length_size = ret; | |||||
| s->extradata_parsed = 1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| HEVCBSFContext *ctx = bsfc->priv_data; | |||||
| HEVCBSFContext *s = ctx->priv_data; | |||||
| AVPacket *in; | |||||
| GetByteContext gb; | GetByteContext gb; | ||||
| uint8_t *out = NULL; | |||||
| size_t out_size = 0; | |||||
| int got_irap = 0; | int got_irap = 0; | ||||
| int i, ret = 0; | int i, ret = 0; | ||||
| if (!ctx->extradata_parsed) { | |||||
| if (avctx->extradata_size < MIN_HEVCC_LENGTH || | |||||
| AV_RB24(avctx->extradata) == 1 || | |||||
| AV_RB32(avctx->extradata) == 1) { | |||||
| if (!ctx->logged_nonmp4_warning) { | |||||
| av_log(avctx, AV_LOG_VERBOSE, | |||||
| "The input looks like it is Annex B already\n"); | |||||
| ctx->logged_nonmp4_warning = 1; | |||||
| } | |||||
| *poutbuf = (uint8_t *)buf; | |||||
| *poutbuf_size = buf_size; | |||||
| return 0; | |||||
| } | |||||
| if (args && strstr(args, "private_spspps_buf")) | |||||
| ctx->private_spspps = 1; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ret = hevc_extradata_to_annexb(ctx, avctx); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ctx->length_size = ret; | |||||
| ctx->extradata_parsed = 1; | |||||
| if (!s->extradata_parsed) { | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| return 0; | |||||
| } | } | ||||
| *poutbuf_size = 0; | |||||
| *poutbuf = NULL; | |||||
| bytestream2_init(&gb, buf, buf_size); | |||||
| bytestream2_init(&gb, in->data, in->size); | |||||
| while (bytestream2_get_bytes_left(&gb)) { | while (bytestream2_get_bytes_left(&gb)) { | ||||
| uint32_t nalu_size = 0; | uint32_t nalu_size = 0; | ||||
| int nalu_type; | int nalu_type; | ||||
| int is_irap, add_extradata, extra_size; | |||||
| int is_irap, add_extradata, extra_size, prev_size; | |||||
| for (i = 0; i < ctx->length_size; i++) | |||||
| for (i = 0; i < s->length_size; i++) | |||||
| nalu_size = (nalu_size << 8) | bytestream2_get_byte(&gb); | nalu_size = (nalu_size << 8) | bytestream2_get_byte(&gb); | ||||
| nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f; | nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f; | ||||
| @@ -166,47 +149,47 @@ static int hevc_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, | |||||
| /* prepend extradata to IRAP frames */ | /* prepend extradata to IRAP frames */ | ||||
| is_irap = nalu_type >= 16 && nalu_type <= 23; | is_irap = nalu_type >= 16 && nalu_type <= 23; | ||||
| add_extradata = is_irap && !got_irap; | add_extradata = is_irap && !got_irap; | ||||
| extra_size = add_extradata * ctx->spspps_size; | |||||
| extra_size = add_extradata * ctx->par_out->extradata_size; | |||||
| got_irap |= is_irap; | got_irap |= is_irap; | ||||
| if (SIZE_MAX - out_size < 4 || | |||||
| SIZE_MAX - out_size - 4 < nalu_size || | |||||
| SIZE_MAX - out_size - 4 - nalu_size < extra_size) { | |||||
| if (SIZE_MAX - nalu_size < 4 || | |||||
| SIZE_MAX - 4 - nalu_size < extra_size) { | |||||
| ret = AVERROR_INVALIDDATA; | ret = AVERROR_INVALIDDATA; | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| ret = av_reallocp(&out, out_size + 4 + nalu_size + extra_size); | |||||
| prev_size = out->size; | |||||
| ret = av_grow_packet(out, 4 + nalu_size + extra_size); | |||||
| if (ret < 0) | if (ret < 0) | ||||
| goto fail; | goto fail; | ||||
| if (add_extradata) | if (add_extradata) | ||||
| memcpy(out + out_size, ctx->spspps_buf, extra_size); | |||||
| AV_WB32(out + out_size + extra_size, 1); | |||||
| bytestream2_get_buffer(&gb, out + out_size + 4 + extra_size, nalu_size); | |||||
| out_size += 4 + nalu_size + extra_size; | |||||
| memcpy(out->data + prev_size, ctx->par_out->extradata, extra_size); | |||||
| AV_WB32(out->data + prev_size + extra_size, 1); | |||||
| bytestream2_get_buffer(&gb, out->data + prev_size + 4 + extra_size, nalu_size); | |||||
| } | } | ||||
| *poutbuf = out; | |||||
| *poutbuf_size = out_size; | |||||
| return 1; | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| fail: | fail: | ||||
| av_freep(&out); | |||||
| if (ret < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| static void hevc_mp4toannexb_close(AVBitStreamFilterContext *bsfc) | |||||
| { | |||||
| HEVCBSFContext *ctx = bsfc->priv_data; | |||||
| if (ctx->private_spspps) | |||||
| av_freep(&ctx->spspps_buf); | |||||
| } | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| AVBitStreamFilter ff_hevc_mp4toannexb_bsf = { | |||||
| "hevc_mp4toannexb", | |||||
| sizeof(HEVCBSFContext), | |||||
| hevc_mp4toannexb_filter, | |||||
| hevc_mp4toannexb_close, | |||||
| const AVBitStreamFilter ff_hevc_mp4toannexb_bsf = { | |||||
| .name = "hevc_mp4toannexb", | |||||
| .priv_data_size = sizeof(HEVCBSFContext), | |||||
| .init = hevc_mp4toannexb_init, | |||||
| .filter = hevc_mp4toannexb_filter, | |||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -26,35 +26,51 @@ | |||||
| */ | */ | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "bytestream.h" | #include "bytestream.h" | ||||
| static int imx_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe) | |||||
| static int imx_dump_header(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| /* MXF essence element key */ | /* MXF essence element key */ | ||||
| static const uint8_t imx_header[16] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x05,0x01,0x01,0x00 }; | static const uint8_t imx_header[16] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x05,0x01,0x01,0x00 }; | ||||
| uint8_t *poutbufp; | |||||
| if (avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO) { | |||||
| av_log(avctx, AV_LOG_ERROR, "imx bitstream filter only applies to mpeg2video codec\n"); | |||||
| return 0; | |||||
| } | |||||
| *poutbuf = av_malloc(buf_size + 20 + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!*poutbuf) | |||||
| return AVERROR(ENOMEM); | |||||
| poutbufp = *poutbuf; | |||||
| bytestream_put_buffer(&poutbufp, imx_header, 16); | |||||
| bytestream_put_byte(&poutbufp, 0x83); /* KLV BER long form */ | |||||
| bytestream_put_be24(&poutbufp, buf_size); | |||||
| bytestream_put_buffer(&poutbufp, buf, buf_size); | |||||
| *poutbuf_size = poutbufp - *poutbuf; | |||||
| return 1; | |||||
| AVPacket *in; | |||||
| int ret = 0; | |||||
| uint8_t *out_buf; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ret = av_new_packet(out, in->size + 20); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| out_buf = out->data; | |||||
| bytestream_put_buffer(&out_buf, imx_header, 16); | |||||
| bytestream_put_byte(&out_buf, 0x83); /* KLV BER long form */ | |||||
| bytestream_put_be24(&out_buf, in->size); | |||||
| bytestream_put_buffer(&out_buf, in->data, in->size); | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| fail: | |||||
| if (ret < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_imx_dump_header_bsf = { | |||||
| .name = "imxdump", | |||||
| .filter = imx_dump_header, | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_imx_dump_header_bsf = { | |||||
| .name = "imxdump", | |||||
| .filter = imx_dump_header, | |||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -31,6 +31,7 @@ | |||||
| #include "libavutil/intreadwrite.h" | #include "libavutil/intreadwrite.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "jpegtables.h" | #include "jpegtables.h" | ||||
| #include "mjpeg.h" | #include "mjpeg.h" | ||||
| @@ -77,46 +78,64 @@ static uint8_t *append_dht_segment(uint8_t *buf) | |||||
| return buf; | return buf; | ||||
| } | } | ||||
| static int mjpeg2jpeg_filter(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int mjpeg2jpeg_filter(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| AVPacket *in; | |||||
| int ret = 0; | |||||
| int input_skip, output_size; | int input_skip, output_size; | ||||
| uint8_t *output, *out; | |||||
| uint8_t *output; | |||||
| if (buf_size < 12) { | |||||
| av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); | |||||
| return AVERROR_INVALIDDATA; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (in->size < 12) { | |||||
| av_log(ctx, AV_LOG_ERROR, "input is truncated\n"); | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| goto fail; | |||||
| } | } | ||||
| if (AV_RB16(buf) != 0xffd8) { | |||||
| av_log(avctx, AV_LOG_ERROR, "input is not MJPEG\n"); | |||||
| return AVERROR_INVALIDDATA; | |||||
| if (AV_RB16(in->data) != 0xffd8) { | |||||
| av_log(ctx, AV_LOG_ERROR, "input is not MJPEG\n"); | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| goto fail; | |||||
| } | } | ||||
| if (buf[2] == 0xff && buf[3] == APP0) { | |||||
| input_skip = (buf[4] << 8) + buf[5] + 4; | |||||
| if (in->data[2] == 0xff && in->data[3] == APP0) { | |||||
| input_skip = (in->data[4] << 8) + in->data[5] + 4; | |||||
| } else { | } else { | ||||
| input_skip = 2; | input_skip = 2; | ||||
| } | } | ||||
| if (buf_size < input_skip) { | |||||
| av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); | |||||
| return AVERROR_INVALIDDATA; | |||||
| if (in->size < input_skip) { | |||||
| av_log(ctx, AV_LOG_ERROR, "input is truncated\n"); | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| goto fail; | |||||
| } | } | ||||
| output_size = buf_size - input_skip + | |||||
| output_size = in->size - input_skip + | |||||
| sizeof(jpeg_header) + dht_segment_size; | sizeof(jpeg_header) + dht_segment_size; | ||||
| output = out = av_malloc(output_size); | |||||
| if (!output) | |||||
| return AVERROR(ENOMEM); | |||||
| out = append(out, jpeg_header, sizeof(jpeg_header)); | |||||
| out = append_dht_segment(out); | |||||
| out = append(out, buf + input_skip, buf_size - input_skip); | |||||
| *poutbuf = output; | |||||
| *poutbuf_size = output_size; | |||||
| return 1; | |||||
| ret = av_new_packet(out, output_size); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| output = out->data; | |||||
| output = append(output, jpeg_header, sizeof(jpeg_header)); | |||||
| output = append_dht_segment(output); | |||||
| output = append(output, in->data + input_skip, in->size - input_skip); | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| fail: | |||||
| if (ret < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_mjpeg2jpeg_bsf = { | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_MJPEG, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_mjpeg2jpeg_bsf = { | |||||
| .name = "mjpeg2jpeg", | .name = "mjpeg2jpeg", | ||||
| .filter = mjpeg2jpeg_filter, | .filter = mjpeg2jpeg_filter, | ||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -26,70 +26,83 @@ | |||||
| */ | */ | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "bytestream.h" | #include "bytestream.h" | ||||
| #include "mjpeg.h" | #include "mjpeg.h" | ||||
| static int mjpega_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe) | |||||
| static int mjpega_dump_header(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| uint8_t *poutbufp; | |||||
| AVPacket *in; | |||||
| uint8_t *out_buf; | |||||
| unsigned dqt = 0, dht = 0, sof0 = 0; | unsigned dqt = 0, dht = 0, sof0 = 0; | ||||
| int i; | |||||
| int ret = 0, i; | |||||
| if (avctx->codec_id != AV_CODEC_ID_MJPEG) { | |||||
| av_log(avctx, AV_LOG_ERROR, "mjpega bitstream filter only applies to mjpeg codec\n"); | |||||
| return 0; | |||||
| } | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ret = av_new_packet(out, in->size + 44); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| *poutbuf_size = 0; | |||||
| *poutbuf = av_malloc(buf_size + 44 + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!*poutbuf) | |||||
| return AVERROR(ENOMEM); | |||||
| poutbufp = *poutbuf; | |||||
| bytestream_put_byte(&poutbufp, 0xff); | |||||
| bytestream_put_byte(&poutbufp, SOI); | |||||
| bytestream_put_byte(&poutbufp, 0xff); | |||||
| bytestream_put_byte(&poutbufp, APP1); | |||||
| bytestream_put_be16(&poutbufp, 42); /* size */ | |||||
| bytestream_put_be32(&poutbufp, 0); | |||||
| bytestream_put_buffer(&poutbufp, "mjpg", 4); | |||||
| bytestream_put_be32(&poutbufp, buf_size + 44); /* field size */ | |||||
| bytestream_put_be32(&poutbufp, buf_size + 44); /* pad field size */ | |||||
| bytestream_put_be32(&poutbufp, 0); /* next ptr */ | |||||
| out_buf = out->data; | |||||
| bytestream_put_byte(&out_buf, 0xff); | |||||
| bytestream_put_byte(&out_buf, SOI); | |||||
| bytestream_put_byte(&out_buf, 0xff); | |||||
| bytestream_put_byte(&out_buf, APP1); | |||||
| bytestream_put_be16(&out_buf, 42); /* size */ | |||||
| bytestream_put_be32(&out_buf, 0); | |||||
| bytestream_put_buffer(&out_buf, "mjpg", 4); | |||||
| bytestream_put_be32(&out_buf, in->size + 44); /* field size */ | |||||
| bytestream_put_be32(&out_buf, in->size + 44); /* pad field size */ | |||||
| bytestream_put_be32(&out_buf, 0); /* next ptr */ | |||||
| for (i = 0; i < buf_size - 1; i++) { | |||||
| if (buf[i] == 0xff) { | |||||
| switch (buf[i + 1]) { | |||||
| for (i = 0; i < in->size - 1; i++) { | |||||
| if (in->data[i] == 0xff) { | |||||
| switch (in->data[i + 1]) { | |||||
| case DQT: dqt = i + 46; break; | case DQT: dqt = i + 46; break; | ||||
| case DHT: dht = i + 46; break; | case DHT: dht = i + 46; break; | ||||
| case SOF0: sof0 = i + 46; break; | case SOF0: sof0 = i + 46; break; | ||||
| case SOS: | case SOS: | ||||
| bytestream_put_be32(&poutbufp, dqt); /* quant off */ | |||||
| bytestream_put_be32(&poutbufp, dht); /* huff off */ | |||||
| bytestream_put_be32(&poutbufp, sof0); /* image off */ | |||||
| bytestream_put_be32(&poutbufp, i + 46); /* scan off */ | |||||
| bytestream_put_be32(&poutbufp, i + 46 + AV_RB16(buf + i + 2)); /* data off */ | |||||
| bytestream_put_buffer(&poutbufp, buf + 2, buf_size - 2); /* skip already written SOI */ | |||||
| *poutbuf_size = poutbufp - *poutbuf; | |||||
| return 1; | |||||
| bytestream_put_be32(&out_buf, dqt); /* quant off */ | |||||
| bytestream_put_be32(&out_buf, dht); /* huff off */ | |||||
| bytestream_put_be32(&out_buf, sof0); /* image off */ | |||||
| bytestream_put_be32(&out_buf, i + 46); /* scan off */ | |||||
| bytestream_put_be32(&out_buf, i + 46 + AV_RB16(in->data + i + 2)); /* data off */ | |||||
| bytestream_put_buffer(&out_buf, in->data + 2, in->size - 2); /* skip already written SOI */ | |||||
| out->size = out_buf - out->data; | |||||
| av_packet_free(&in); | |||||
| return 0; | |||||
| case APP1: | case APP1: | ||||
| if (i + 8 < buf_size && AV_RL32(buf + i + 8) == AV_RL32("mjpg")) { | |||||
| av_log(avctx, AV_LOG_ERROR, "bitstream already formatted\n"); | |||||
| memcpy(*poutbuf, buf, buf_size); | |||||
| *poutbuf_size = buf_size; | |||||
| return 1; | |||||
| if (i + 8 < in->size && AV_RL32(in->data + i + 8) == AV_RL32("mjpg")) { | |||||
| av_log(ctx, AV_LOG_ERROR, "bitstream already formatted\n"); | |||||
| av_packet_unref(out); | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| return 0; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| av_freep(poutbuf); | |||||
| av_log(avctx, AV_LOG_ERROR, "could not find SOS marker in bitstream\n"); | |||||
| return 0; | |||||
| av_log(ctx, AV_LOG_ERROR, "could not find SOS marker in bitstream\n"); | |||||
| fail: | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return AVERROR_INVALIDDATA; | |||||
| } | } | ||||
| AVBitStreamFilter ff_mjpega_dump_header_bsf = { | |||||
| .name = "mjpegadump", | |||||
| .filter = mjpega_dump_header, | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_MJPEG, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_mjpega_dump_header_bsf = { | |||||
| .name = "mjpegadump", | |||||
| .filter = mjpega_dump_header, | |||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -21,39 +21,79 @@ | |||||
| #include "libavutil/common.h" | #include "libavutil/common.h" | ||||
| #include "libavutil/intreadwrite.h" | #include "libavutil/intreadwrite.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| static int text2movsub(AVBSFContext *ctx, AVPacket *out) | |||||
| { | |||||
| AVPacket *in; | |||||
| int ret = 0; | |||||
| static int text2movsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe){ | |||||
| if (buf_size > 0xffff) return 0; | |||||
| *poutbuf_size = buf_size + 2; | |||||
| *poutbuf = av_malloc(*poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!*poutbuf) | |||||
| return AVERROR(ENOMEM); | |||||
| AV_WB16(*poutbuf, buf_size); | |||||
| memcpy(*poutbuf + 2, buf, buf_size); | |||||
| return 1; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| if (in->size > 0xffff) { | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| goto fail; | |||||
| } | |||||
| ret = av_new_packet(out, in->size + 2); | |||||
| if (ret < 0) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| AV_WB16(out->data, in->size); | |||||
| memcpy(out->data + 2, in->data, in->size); | |||||
| fail: | |||||
| if (ret < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_text2movsub_bsf={ | |||||
| const AVBitStreamFilter ff_text2movsub_bsf = { | |||||
| .name = "text2movsub", | .name = "text2movsub", | ||||
| .filter = text2movsub, | .filter = text2movsub, | ||||
| }; | }; | ||||
| static int mov2textsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe){ | |||||
| if (buf_size < 2) return 0; | |||||
| *poutbuf_size = FFMIN(buf_size - 2, AV_RB16(buf)); | |||||
| *poutbuf = av_malloc(*poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!*poutbuf) | |||||
| return AVERROR(ENOMEM); | |||||
| memcpy(*poutbuf, buf + 2, *poutbuf_size); | |||||
| return 1; | |||||
| static int mov2textsub(AVBSFContext *ctx, AVPacket *out) | |||||
| { | |||||
| AVPacket *in; | |||||
| int ret = 0; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| if (in->size < 2) { | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| goto fail; | |||||
| } | |||||
| ret = av_new_packet(out, FFMIN(in->size - 2, AV_RB16(in->data))); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| memcpy(out->data, in->data + 2, out->size); | |||||
| fail: | |||||
| if (ret < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_mov2textsub_bsf={ | |||||
| const AVBitStreamFilter ff_mov2textsub_bsf = { | |||||
| .name = "mov2textsub", | .name = "mov2textsub", | ||||
| .filter = mov2textsub, | .filter = mov2textsub, | ||||
| }; | }; | ||||
| @@ -21,32 +21,43 @@ | |||||
| #include "libavutil/common.h" | #include "libavutil/common.h" | ||||
| #include "libavutil/intreadwrite.h" | #include "libavutil/intreadwrite.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "mpegaudiodecheader.h" | #include "mpegaudiodecheader.h" | ||||
| #include "mpegaudiodata.h" | #include "mpegaudiodata.h" | ||||
| static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe){ | |||||
| static int mp3_header_decompress(AVBSFContext *ctx, AVPacket *out) | |||||
| { | |||||
| AVPacket *in; | |||||
| uint32_t header; | uint32_t header; | ||||
| int sample_rate= avctx->sample_rate; | |||||
| int sample_rate= ctx->par_in->sample_rate; | |||||
| int sample_rate_index=0; | int sample_rate_index=0; | ||||
| int lsf, mpeg25, bitrate_index, frame_size; | |||||
| int lsf, mpeg25, bitrate_index, frame_size, ret; | |||||
| uint8_t *buf; | |||||
| int buf_size; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| buf = in->data; | |||||
| buf_size = in->size; | |||||
| header = AV_RB32(buf); | header = AV_RB32(buf); | ||||
| if(ff_mpa_check_header(header) >= 0){ | if(ff_mpa_check_header(header) >= 0){ | ||||
| *poutbuf= (uint8_t *) buf; | |||||
| *poutbuf_size= buf_size; | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| if(avctx->extradata_size != 15 || strcmp(avctx->extradata, "FFCMP3 0.0")){ | |||||
| av_log(avctx, AV_LOG_ERROR, "Extradata invalid %d\n", avctx->extradata_size); | |||||
| return -1; | |||||
| if(ctx->par_in->extradata_size != 15 || strcmp(ctx->par_in->extradata, "FFCMP3 0.0")){ | |||||
| av_log(ctx, AV_LOG_ERROR, "Extradata invalid %d\n", ctx->par_in->extradata_size); | |||||
| ret = AVERROR(EINVAL); | |||||
| goto fail; | |||||
| } | } | ||||
| header= AV_RB32(avctx->extradata+11) & MP3_MASK; | |||||
| header= AV_RB32(ctx->par_in->extradata+11) & MP3_MASK; | |||||
| lsf = sample_rate < (24000+32000)/2; | lsf = sample_rate < (24000+32000)/2; | ||||
| mpeg25 = sample_rate < (12000+16000)/2; | mpeg25 = sample_rate < (12000+16000)/2; | ||||
| @@ -62,20 +73,27 @@ static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext | |||||
| break; | break; | ||||
| } | } | ||||
| if(bitrate_index == 30){ | if(bitrate_index == 30){ | ||||
| av_log(avctx, AV_LOG_ERROR, "Could not find bitrate_index.\n"); | |||||
| return -1; | |||||
| av_log(ctx, AV_LOG_ERROR, "Could not find bitrate_index.\n"); | |||||
| ret = AVERROR(EINVAL); | |||||
| goto fail; | |||||
| } | } | ||||
| header |= (bitrate_index&1)<<9; | header |= (bitrate_index&1)<<9; | ||||
| header |= (bitrate_index>>1)<<12; | header |= (bitrate_index>>1)<<12; | ||||
| header |= (frame_size == buf_size + 4)<<16; //FIXME actually set a correct crc instead of 0 | header |= (frame_size == buf_size + 4)<<16; //FIXME actually set a correct crc instead of 0 | ||||
| *poutbuf_size= frame_size; | |||||
| *poutbuf= av_malloc(frame_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| memcpy(*poutbuf + frame_size - buf_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| ret = av_new_packet(out, frame_size); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) { | |||||
| av_packet_free(&out); | |||||
| goto fail; | |||||
| } | |||||
| memcpy(out->data + frame_size - buf_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if(avctx->channels==2){ | |||||
| uint8_t *p= *poutbuf + frame_size - buf_size; | |||||
| if(ctx->par_in->channels==2){ | |||||
| uint8_t *p= out->data + frame_size - buf_size; | |||||
| if(lsf){ | if(lsf){ | ||||
| FFSWAP(int, p[1], p[2]); | FFSWAP(int, p[1], p[2]); | ||||
| header |= (p[1] & 0xC0)>>2; | header |= (p[1] & 0xC0)>>2; | ||||
| @@ -86,12 +104,21 @@ static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext | |||||
| } | } | ||||
| } | } | ||||
| AV_WB32(*poutbuf, header); | |||||
| AV_WB32(out->data, header); | |||||
| return 1; | |||||
| ret = 0; | |||||
| fail: | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_mp3_header_decompress_bsf={ | |||||
| .name = "mp3decomp", | |||||
| .filter = mp3_header_decompress, | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_MP3, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_mp3_header_decompress_bsf = { | |||||
| .name = "mp3decomp", | |||||
| .filter = mp3_header_decompress, | |||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -20,12 +20,12 @@ | |||||
| */ | */ | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "mpeg4video.h" | #include "mpeg4video.h" | ||||
| typedef struct UnpackBFramesBSFContext { | typedef struct UnpackBFramesBSFContext { | ||||
| uint8_t *b_frame_buf; | uint8_t *b_frame_buf; | ||||
| int b_frame_buf_size; | int b_frame_buf_size; | ||||
| int updated_extradata; | |||||
| } UnpackBFramesBSFContext; | } UnpackBFramesBSFContext; | ||||
| /* search next start code */ | /* search next start code */ | ||||
| @@ -83,112 +83,109 @@ static uint8_t *create_new_buffer(const uint8_t *src, int size) { | |||||
| return dst; | return dst; | ||||
| } | } | ||||
| static int mpeg4_unpack_bframes_filter(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| UnpackBFramesBSFContext *ctx = bsfc->priv_data; | |||||
| UnpackBFramesBSFContext *s = ctx->priv_data; | |||||
| int pos_p = -1, nb_vop = 0, pos_vop2 = -1, ret = 0; | int pos_p = -1, nb_vop = 0, pos_vop2 = -1, ret = 0; | ||||
| AVPacket *in; | |||||
| if (avctx->codec_id != AV_CODEC_ID_MPEG4) { | |||||
| av_log(avctx, AV_LOG_ERROR, | |||||
| "The mpeg4_unpack_bframes bitstream filter is only useful for mpeg4.\n"); | |||||
| return AVERROR(EINVAL); | |||||
| } | |||||
| if (!ctx->updated_extradata && avctx->extradata) { | |||||
| int pos_p_ext = -1; | |||||
| scan_buffer(avctx->extradata, avctx->extradata_size, &pos_p_ext, NULL, NULL); | |||||
| if (pos_p_ext >= 0) { | |||||
| av_log(avctx, AV_LOG_DEBUG, | |||||
| "Updating DivX userdata (remove trailing 'p') in extradata.\n"); | |||||
| avctx->extradata[pos_p_ext] = '\0'; | |||||
| } | |||||
| ctx->updated_extradata = 1; | |||||
| } | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| scan_buffer(buf, buf_size, &pos_p, &nb_vop, &pos_vop2); | |||||
| av_log(avctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop); | |||||
| scan_buffer(in->data, in->size, &pos_p, &nb_vop, &pos_vop2); | |||||
| av_log(ctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop); | |||||
| if (pos_vop2 >= 0) { | if (pos_vop2 >= 0) { | ||||
| if (ctx->b_frame_buf) { | |||||
| av_log(avctx, AV_LOG_WARNING, | |||||
| if (s->b_frame_buf) { | |||||
| av_log(ctx, AV_LOG_WARNING, | |||||
| "Missing one N-VOP packet, discarding one B-frame.\n"); | "Missing one N-VOP packet, discarding one B-frame.\n"); | ||||
| av_freep(&ctx->b_frame_buf); | |||||
| ctx->b_frame_buf_size = 0; | |||||
| av_freep(&s->b_frame_buf); | |||||
| s->b_frame_buf_size = 0; | |||||
| } | } | ||||
| /* store the packed B-frame in the BSFContext */ | /* store the packed B-frame in the BSFContext */ | ||||
| ctx->b_frame_buf_size = buf_size - pos_vop2; | |||||
| ctx->b_frame_buf = create_new_buffer(buf + pos_vop2, ctx->b_frame_buf_size); | |||||
| if (!ctx->b_frame_buf) { | |||||
| ctx->b_frame_buf_size = 0; | |||||
| s->b_frame_buf_size = in->size - pos_vop2; | |||||
| s->b_frame_buf = create_new_buffer(in->data + pos_vop2, s->b_frame_buf_size); | |||||
| if (!s->b_frame_buf) { | |||||
| s->b_frame_buf_size = 0; | |||||
| av_packet_free(&in); | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| } | } | ||||
| } | } | ||||
| if (nb_vop > 2) { | if (nb_vop > 2) { | ||||
| av_log(avctx, AV_LOG_WARNING, | |||||
| av_log(ctx, AV_LOG_WARNING, | |||||
| "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop); | "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop); | ||||
| } | } | ||||
| if (nb_vop == 1 && ctx->b_frame_buf) { | |||||
| if (nb_vop == 1 && s->b_frame_buf) { | |||||
| /* use frame from BSFContext */ | /* use frame from BSFContext */ | ||||
| *poutbuf = ctx->b_frame_buf; | |||||
| *poutbuf_size = ctx->b_frame_buf_size; | |||||
| /* the output buffer is distinct from the input buffer */ | |||||
| ret = 1; | |||||
| if (buf_size <= MAX_NVOP_SIZE) { | |||||
| av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size); | |||||
| if (in->size <= MAX_NVOP_SIZE) { | |||||
| /* N-VOP */ | /* N-VOP */ | ||||
| av_log(avctx, AV_LOG_DEBUG, "Skipping N-VOP.\n"); | |||||
| ctx->b_frame_buf = NULL; | |||||
| ctx->b_frame_buf_size = 0; | |||||
| av_log(ctx, AV_LOG_DEBUG, "Skipping N-VOP.\n"); | |||||
| s->b_frame_buf = NULL; | |||||
| s->b_frame_buf_size = 0; | |||||
| } else { | } else { | ||||
| /* copy packet into BSFContext */ | /* copy packet into BSFContext */ | ||||
| ctx->b_frame_buf_size = buf_size; | |||||
| ctx->b_frame_buf = create_new_buffer(buf , buf_size); | |||||
| if (!ctx->b_frame_buf) { | |||||
| ctx->b_frame_buf_size = 0; | |||||
| av_freep(poutbuf); | |||||
| *poutbuf_size = 0; | |||||
| s->b_frame_buf_size = in->size; | |||||
| s->b_frame_buf = create_new_buffer(in->data, in->size); | |||||
| if (!s->b_frame_buf) { | |||||
| s->b_frame_buf_size = 0; | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| } | } | ||||
| } | } | ||||
| } else if (nb_vop >= 2) { | } else if (nb_vop >= 2) { | ||||
| /* use first frame of the packet */ | /* use first frame of the packet */ | ||||
| *poutbuf = (uint8_t *) buf; | |||||
| *poutbuf_size = pos_vop2; | |||||
| av_packet_move_ref(out, in); | |||||
| out->size = pos_vop2; | |||||
| } else if (pos_p >= 0) { | } else if (pos_p >= 0) { | ||||
| av_log(avctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n"); | |||||
| *poutbuf_size = buf_size; | |||||
| *poutbuf = create_new_buffer(buf, buf_size); | |||||
| if (!*poutbuf) { | |||||
| *poutbuf_size = 0; | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| av_log(ctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n"); | |||||
| av_packet_move_ref(out, in); | |||||
| /* remove 'p' (packed) from the end of the (DivX) userdata string */ | /* remove 'p' (packed) from the end of the (DivX) userdata string */ | ||||
| (*poutbuf)[pos_p] = '\0'; | |||||
| /* the output buffer is distinct from the input buffer */ | |||||
| ret = 1; | |||||
| out->data[pos_p] = '\0'; | |||||
| } else { | } else { | ||||
| /* copy packet */ | /* copy packet */ | ||||
| *poutbuf = (uint8_t *) buf; | |||||
| *poutbuf_size = buf_size; | |||||
| av_packet_move_ref(out, in); | |||||
| } | |||||
| av_packet_free(&in); | |||||
| return 0; | |||||
| } | |||||
| static int mpeg4_unpack_bframes_init(AVBSFContext *ctx) | |||||
| { | |||||
| if (ctx->par_in->extradata) { | |||||
| int pos_p_ext = -1; | |||||
| scan_buffer(ctx->par_in->extradata, ctx->par_in->extradata_size, &pos_p_ext, NULL, NULL); | |||||
| if (pos_p_ext >= 0) { | |||||
| av_log(ctx, AV_LOG_DEBUG, | |||||
| "Updating DivX userdata (remove trailing 'p') in extradata.\n"); | |||||
| ctx->par_out->extradata[pos_p_ext] = '\0'; | |||||
| } | |||||
| } | } | ||||
| return ret; | |||||
| return 0; | |||||
| } | } | ||||
| static void mpeg4_unpack_bframes_close(AVBitStreamFilterContext *bsfc) | |||||
| static void mpeg4_unpack_bframes_close(AVBSFContext *bsfc) | |||||
| { | { | ||||
| UnpackBFramesBSFContext *ctx = bsfc->priv_data; | UnpackBFramesBSFContext *ctx = bsfc->priv_data; | ||||
| av_freep(&ctx->b_frame_buf); | av_freep(&ctx->b_frame_buf); | ||||
| } | } | ||||
| AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf = { | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_MPEG4, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf = { | |||||
| .name = "mpeg4_unpack_bframes", | .name = "mpeg4_unpack_bframes", | ||||
| .priv_data_size = sizeof(UnpackBFramesBSFContext), | .priv_data_size = sizeof(UnpackBFramesBSFContext), | ||||
| .init = mpeg4_unpack_bframes_init, | |||||
| .filter = mpeg4_unpack_bframes_filter, | .filter = mpeg4_unpack_bframes_filter, | ||||
| .close = mpeg4_unpack_bframes_close | |||||
| .close = mpeg4_unpack_bframes_close, | |||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -22,34 +22,70 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "libavutil/log.h" | |||||
| #include "libavutil/mem.h" | #include "libavutil/mem.h" | ||||
| #include "libavutil/opt.h" | |||||
| typedef struct NoiseContext { | |||||
| const AVClass *class; | |||||
| int amount; | |||||
| unsigned int state; | |||||
| } NoiseContext; | |||||
| static int noise(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe){ | |||||
| unsigned int *state= bsfc->priv_data; | |||||
| int amount= args ? atoi(args) : (*state % 10001+1); | |||||
| int i; | |||||
| static int noise(AVBSFContext *ctx, AVPacket *out) | |||||
| { | |||||
| NoiseContext *s = ctx->priv_data; | |||||
| AVPacket *in; | |||||
| int amount = s->amount > 0 ? s->amount : (s->state % 10001 + 1); | |||||
| int i, ret = 0; | |||||
| if(amount <= 0) | |||||
| if (amount <= 0) | |||||
| return AVERROR(EINVAL); | return AVERROR(EINVAL); | ||||
| *poutbuf= av_malloc(buf_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!*poutbuf) | |||||
| return AVERROR(ENOMEM); | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ret = av_new_packet(out, in->size); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = av_packet_copy_props(out, in); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| memcpy(out->data, in->data, in->size); | |||||
| memcpy(*poutbuf, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); | |||||
| for(i=0; i<buf_size; i++){ | |||||
| (*state) += (*poutbuf)[i] + 1; | |||||
| if(*state % amount == 0) | |||||
| (*poutbuf)[i] = *state; | |||||
| for (i = 0; i < out->size; i++) { | |||||
| s->state += out->data[i] + 1; | |||||
| if (s->state % amount == 0) | |||||
| out->data[i] = s->state; | |||||
| } | } | ||||
| return 1; | |||||
| fail: | |||||
| if (ret < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return ret; | |||||
| } | } | ||||
| AVBitStreamFilter ff_noise_bsf={ | |||||
| #define OFFSET(x) offsetof(NoiseContext, x) | |||||
| static const AVOption options[] = { | |||||
| { "amount", NULL, OFFSET(amount), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX }, | |||||
| { NULL }, | |||||
| }; | |||||
| static const AVClass noise_class = { | |||||
| .class_name = "noise", | |||||
| .item_name = av_default_item_name, | |||||
| .option = options, | |||||
| .version = LIBAVUTIL_VERSION_INT, | |||||
| }; | |||||
| const AVBitStreamFilter ff_noise_bsf = { | |||||
| .name = "noise", | .name = "noise", | ||||
| .priv_data_size = sizeof(int), | .priv_data_size = sizeof(int), | ||||
| .priv_class = &noise_class, | |||||
| .filter = noise, | .filter = noise, | ||||
| }; | }; | ||||
| @@ -18,38 +18,99 @@ | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| #include "libavutil/log.h" | |||||
| #include "libavutil/opt.h" | |||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| enum RemoveFreq { | |||||
| REMOVE_FREQ_KEYFRAME, | |||||
| REMOVE_FREQ_ALL, | |||||
| }; | |||||
| static int remove_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, int keyframe){ | |||||
| int cmd= args ? *args : 0; | |||||
| AVCodecParserContext *s; | |||||
| typedef struct RemoveExtradataContext { | |||||
| const AVClass *class; | |||||
| int freq; | |||||
| if(!bsfc->parser){ | |||||
| bsfc->parser= av_parser_init(avctx->codec_id); | |||||
| } | |||||
| s= bsfc->parser; | |||||
| if(s && s->parser->split){ | |||||
| if( (((avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) || | |||||
| (avctx->flags2 & AV_CODEC_FLAG2_LOCAL_HEADER)) && cmd == 'a') | |||||
| ||(!keyframe && cmd=='k') | |||||
| ||(cmd=='e' || !cmd) | |||||
| ){ | |||||
| int i= s->parser->split(avctx, buf, buf_size); | |||||
| buf += i; | |||||
| buf_size -= i; | |||||
| AVCodecParserContext *parser; | |||||
| AVCodecContext *avctx; | |||||
| } RemoveExtradataContext; | |||||
| static int remove_extradata(AVBSFContext *ctx, AVPacket *out) | |||||
| { | |||||
| RemoveExtradataContext *s = ctx->priv_data; | |||||
| AVPacket *in; | |||||
| int ret; | |||||
| ret = ff_bsf_get_packet(ctx, &in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| if (s->parser && s->parser->parser->split) { | |||||
| if (s->freq == REMOVE_FREQ_ALL || | |||||
| (s->freq == REMOVE_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY)) { | |||||
| int i = s->parser->parser->split(s->avctx, in->data, in->size); | |||||
| in->data += i; | |||||
| in->size -= i; | |||||
| } | } | ||||
| } | } | ||||
| *poutbuf= (uint8_t *) buf; | |||||
| *poutbuf_size= buf_size; | |||||
| av_packet_move_ref(out, in); | |||||
| av_packet_free(&in); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| AVBitStreamFilter ff_remove_extradata_bsf={ | |||||
| .name = "remove_extra", | |||||
| .filter = remove_extradata, | |||||
| static int remove_extradata_init(AVBSFContext *ctx) | |||||
| { | |||||
| RemoveExtradataContext *s = ctx->priv_data; | |||||
| int ret; | |||||
| s->parser = av_parser_init(ctx->par_in->codec_id); | |||||
| if (s->parser) { | |||||
| s->avctx = avcodec_alloc_context3(NULL); | |||||
| if (!s->avctx) | |||||
| return AVERROR(ENOMEM); | |||||
| ret = avcodec_parameters_to_context(s->avctx, ctx->par_in); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static void remove_extradata_close(AVBSFContext *ctx) | |||||
| { | |||||
| RemoveExtradataContext *s = ctx->priv_data; | |||||
| avcodec_free_context(&s->avctx); | |||||
| av_parser_close(s->parser); | |||||
| } | |||||
| #define OFFSET(x) offsetof(RemoveExtradataContext, x) | |||||
| static const AVOption options[] = { | |||||
| { "freq", NULL, OFFSET(freq), AV_OPT_TYPE_INT, { .i64 = REMOVE_FREQ_KEYFRAME }, REMOVE_FREQ_KEYFRAME, REMOVE_FREQ_ALL, 0, "freq" }, | |||||
| { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_KEYFRAME }, .unit = "freq" }, | |||||
| { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .unit = "freq" }, | |||||
| { NULL }, | |||||
| }; | |||||
| static const AVClass remove_extradata_class = { | |||||
| .class_name = "remove_extradata", | |||||
| .item_name = av_default_item_name, | |||||
| .option = options, | |||||
| .version = LIBAVUTIL_VERSION_INT, | |||||
| }; | |||||
| const AVBitStreamFilter ff_remove_extradata_bsf = { | |||||
| .name = "remove_extra", | |||||
| .priv_data_size = sizeof(RemoveExtradataContext), | |||||
| .priv_class = &remove_extradata_class, | |||||
| .init = remove_extradata_init, | |||||
| .close = remove_extradata_close, | |||||
| .filter = remove_extradata, | |||||
| }; | }; | ||||
| @@ -28,8 +28,8 @@ | |||||
| #include "libavutil/version.h" | #include "libavutil/version.h" | ||||
| #define LIBAVCODEC_VERSION_MAJOR 57 | #define LIBAVCODEC_VERSION_MAJOR 57 | ||||
| #define LIBAVCODEC_VERSION_MINOR 34 | |||||
| #define LIBAVCODEC_VERSION_MICRO 102 | |||||
| #define LIBAVCODEC_VERSION_MINOR 35 | |||||
| #define LIBAVCODEC_VERSION_MICRO 100 | |||||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||
| LIBAVCODEC_VERSION_MINOR, \ | LIBAVCODEC_VERSION_MINOR, \ | ||||
| @@ -214,5 +214,8 @@ | |||||
| #ifndef FF_API_ASS_TIMING | #ifndef FF_API_ASS_TIMING | ||||
| #define FF_API_ASS_TIMING (LIBAVCODEC_VERSION_MAJOR < 59) | #define FF_API_ASS_TIMING (LIBAVCODEC_VERSION_MAJOR < 59) | ||||
| #endif | #endif | ||||
| #ifndef FF_API_OLD_BSF | |||||
| #define FF_API_OLD_BSF (LIBAVCODEC_VERSION_MAJOR < 59) | |||||
| #endif | |||||
| #endif /* AVCODEC_VERSION_H */ | #endif /* AVCODEC_VERSION_H */ | ||||
| @@ -21,6 +21,7 @@ | |||||
| #include "libavutil/avassert.h" | #include "libavutil/avassert.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bsf.h" | |||||
| #include "get_bits.h" | #include "get_bits.h" | ||||
| #define MAX_CACHE 8 | #define MAX_CACHE 8 | ||||
| @@ -50,20 +51,20 @@ static void stats(const struct CachedBuf *in, int n_in, | |||||
| *_sum = sum; | *_sum = sum; | ||||
| } | } | ||||
| static int merge_superframe(const struct CachedBuf *in, int n_in, | |||||
| uint8_t **poutbuf, int *poutbuf_size) | |||||
| static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out) | |||||
| { | { | ||||
| unsigned max, sum, mag, marker, n, sz; | unsigned max, sum, mag, marker, n, sz; | ||||
| uint8_t *ptr; | uint8_t *ptr; | ||||
| int res; | |||||
| stats(in, n_in, &max, &sum); | stats(in, n_in, &max, &sum); | ||||
| mag = av_log2(max) >> 3; | mag = av_log2(max) >> 3; | ||||
| marker = 0xC0 + (mag << 3) + (n_in - 1); | marker = 0xC0 + (mag << 3) + (n_in - 1); | ||||
| sz = *poutbuf_size = sum + 2 + (mag + 1) * n_in; | |||||
| ptr = *poutbuf = av_malloc(sz); | |||||
| if (!ptr) | |||||
| return AVERROR(ENOMEM); | |||||
| sz = sum + 2 + (mag + 1) * n_in; | |||||
| res = av_new_packet(out, sz); | |||||
| if (res < 0) | |||||
| return res; | |||||
| ptr = out->data; | |||||
| for (n = 0; n < n_in; n++) { | for (n = 0; n < n_in; n++) { | ||||
| memcpy(ptr, in[n].data, in[n].size); | memcpy(ptr, in[n].data, in[n].size); | ||||
| ptr += in[n].size; | ptr += in[n].size; | ||||
| @@ -92,31 +93,32 @@ static int merge_superframe(const struct CachedBuf *in, int n_in, | |||||
| break; | break; | ||||
| } | } | ||||
| *ptr++ = marker; | *ptr++ = marker; | ||||
| av_assert0(ptr == &(*poutbuf)[*poutbuf_size]); | |||||
| av_assert0(ptr == &out->data[out->size]); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int vp9_superframe_filter(AVBitStreamFilterContext *bsfc, | |||||
| AVCodecContext *avctx, const char *args, | |||||
| uint8_t **poutbuf, int *poutbuf_size, | |||||
| const uint8_t *buf, int buf_size, | |||||
| int keyframe) | |||||
| static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) | |||||
| { | { | ||||
| GetBitContext gb; | GetBitContext gb; | ||||
| VP9BSFContext *ctx = bsfc->priv_data; | |||||
| VP9BSFContext *s = ctx->priv_data; | |||||
| AVPacket *in; | |||||
| int res, invisible, profile, marker, uses_superframe_syntax = 0, n; | int res, invisible, profile, marker, uses_superframe_syntax = 0, n; | ||||
| marker = buf[buf_size - 1]; | |||||
| res = ff_bsf_get_packet(ctx, &in); | |||||
| if (res < 0) | |||||
| return res; | |||||
| marker = in->data[in->size - 1]; | |||||
| if ((marker & 0xe0) == 0xc0) { | if ((marker & 0xe0) == 0xc0) { | ||||
| int nbytes = 1 + ((marker >> 3) & 0x3); | int nbytes = 1 + ((marker >> 3) & 0x3); | ||||
| int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; | int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; | ||||
| uses_superframe_syntax = buf_size >= idx_sz && buf[buf_size - idx_sz] == marker; | |||||
| uses_superframe_syntax = in->size >= idx_sz && in->data[in->size - idx_sz] == marker; | |||||
| } | } | ||||
| if ((res = init_get_bits8(&gb, buf, buf_size)) < 0) | |||||
| return res; | |||||
| if ((res = init_get_bits8(&gb, in->data, in->size)) < 0) | |||||
| goto done; | |||||
| get_bits(&gb, 2); // frame marker | get_bits(&gb, 2); // frame marker | ||||
| profile = get_bits1(&gb); | profile = get_bits1(&gb); | ||||
| @@ -130,60 +132,74 @@ static int vp9_superframe_filter(AVBitStreamFilterContext *bsfc, | |||||
| invisible = !get_bits1(&gb); | invisible = !get_bits1(&gb); | ||||
| } | } | ||||
| if (uses_superframe_syntax && ctx->n_cache > 0) { | |||||
| av_log(avctx, AV_LOG_ERROR, | |||||
| if (uses_superframe_syntax && s->n_cache > 0) { | |||||
| av_log(ctx, AV_LOG_ERROR, | |||||
| "Mixing of superframe syntax and naked VP9 frames not supported"); | "Mixing of superframe syntax and naked VP9 frames not supported"); | ||||
| return AVERROR_INVALIDDATA; | |||||
| } else if ((!invisible || uses_superframe_syntax) && !ctx->n_cache) { | |||||
| res = AVERROR_INVALIDDATA; | |||||
| goto done; | |||||
| } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) { | |||||
| // passthrough | // passthrough | ||||
| *poutbuf = (uint8_t *) buf; | |||||
| *poutbuf_size = buf_size; | |||||
| return 0; | |||||
| } else if (ctx->n_cache + 1 >= MAX_CACHE) { | |||||
| av_log(avctx, AV_LOG_ERROR, | |||||
| av_packet_move_ref(out, in); | |||||
| goto done; | |||||
| } else if (s->n_cache + 1 >= MAX_CACHE) { | |||||
| av_log(ctx, AV_LOG_ERROR, | |||||
| "Too many invisible frames"); | "Too many invisible frames"); | ||||
| return AVERROR_INVALIDDATA; | |||||
| res = AVERROR_INVALIDDATA; | |||||
| goto done; | |||||
| } | } | ||||
| ctx->cache[ctx->n_cache].size = buf_size; | |||||
| s->cache[s->n_cache].size = in->size; | |||||
| if (invisible && !uses_superframe_syntax) { | if (invisible && !uses_superframe_syntax) { | ||||
| ctx->cache[ctx->n_cache].data = av_malloc(buf_size); | |||||
| if (!ctx->cache[ctx->n_cache].data) | |||||
| return AVERROR(ENOMEM); | |||||
| memcpy(ctx->cache[ctx->n_cache++].data, buf, buf_size); | |||||
| *poutbuf = NULL; | |||||
| *poutbuf_size = 0; | |||||
| return 0; | |||||
| s->cache[s->n_cache].data = av_malloc(in->size); | |||||
| if (!s->cache[s->n_cache].data) { | |||||
| res = AVERROR(ENOMEM); | |||||
| goto done; | |||||
| } | |||||
| memcpy(s->cache[s->n_cache++].data, in->data, in->size); | |||||
| res = AVERROR(EAGAIN); | |||||
| goto done; | |||||
| } | } | ||||
| av_assert0(ctx->n_cache > 0); | |||||
| av_assert0(s->n_cache > 0); | |||||
| ctx->cache[ctx->n_cache].data = (uint8_t *) buf; | |||||
| s->cache[s->n_cache].data = in->data; | |||||
| // build superframe | // build superframe | ||||
| if ((res = merge_superframe(ctx->cache, ctx->n_cache + 1, | |||||
| poutbuf, poutbuf_size)) < 0) | |||||
| return res; | |||||
| for (n = 0; n < ctx->n_cache; n++) | |||||
| av_freep(&ctx->cache[n].data); | |||||
| ctx->n_cache = 0; | |||||
| return 0; | |||||
| if ((res = merge_superframe(s->cache, s->n_cache + 1, out)) < 0) | |||||
| goto done; | |||||
| for (n = 0; n < s->n_cache; n++) | |||||
| av_freep(&s->cache[n].data); | |||||
| s->n_cache = 0; | |||||
| res = av_packet_copy_props(out, in); | |||||
| if (res < 0) | |||||
| goto done; | |||||
| done: | |||||
| if (res < 0) | |||||
| av_packet_unref(out); | |||||
| av_packet_free(&in); | |||||
| return res; | |||||
| } | } | ||||
| static void vp9_superframe_close(AVBitStreamFilterContext *bsfc) | |||||
| static void vp9_superframe_close(AVBSFContext *ctx) | |||||
| { | { | ||||
| VP9BSFContext *ctx = bsfc->priv_data; | |||||
| VP9BSFContext *s = ctx->priv_data; | |||||
| int n; | int n; | ||||
| // free cached data | // free cached data | ||||
| for (n = 0; n < ctx->n_cache; n++) | |||||
| av_freep(&ctx->cache[n].data); | |||||
| for (n = 0; n < s->n_cache; n++) | |||||
| av_freep(&s->cache[n].data); | |||||
| } | } | ||||
| AVBitStreamFilter ff_vp9_superframe_bsf = { | |||||
| static const enum AVCodecID codec_ids[] = { | |||||
| AV_CODEC_ID_VP9, AV_CODEC_ID_NONE, | |||||
| }; | |||||
| const AVBitStreamFilter ff_vp9_superframe_bsf = { | |||||
| .name = "vp9_superframe", | .name = "vp9_superframe", | ||||
| .priv_data_size = sizeof(VP9BSFContext), | .priv_data_size = sizeof(VP9BSFContext), | ||||
| .filter = vp9_superframe_filter, | .filter = vp9_superframe_filter, | ||||
| .close = vp9_superframe_close, | .close = vp9_superframe_close, | ||||
| .codec_ids = codec_ids, | |||||
| }; | }; | ||||
| @@ -309,6 +309,12 @@ FF_DISABLE_DEPRECATION_WARNINGS | |||||
| FF_ENABLE_DEPRECATION_WARNINGS | FF_ENABLE_DEPRECATION_WARNINGS | ||||
| #endif | #endif | ||||
| /* update internal context from codecpar, old bsf api needs this | |||||
| * FIXME: remove when autobsf uses new bsf API */ | |||||
| ret = avcodec_parameters_to_context(st->internal->avctx, st->codecpar); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| if (!st->time_base.num) { | if (!st->time_base.num) { | ||||
| /* fall back on the default timebase values */ | /* fall back on the default timebase values */ | ||||
| if (par->codec_type == AVMEDIA_TYPE_AUDIO && par->sample_rate) | if (par->codec_type == AVMEDIA_TYPE_AUDIO && par->sample_rate) | ||||