mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
Merge commit '33d18982fa03feb061c8f744a4f0a9175c1f63ab'
* 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>
This commit is contained in:
commit
af9cac1be1
2
configure
vendored
2
configure
vendored
@ -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,
|
static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
|
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;
|
init_get_bits(&gb, in->data, AAC_ADTS_HEADER_SIZE * 8);
|
||||||
*poutbuf_size = buf_size;
|
|
||||||
|
|
||||||
if (avctx->extradata)
|
if (bsfc->par_in->extradata && show_bits(&gb, 12) != 0xfff)
|
||||||
if (show_bits(&gb, 12) != 0xfff)
|
goto finish;
|
||||||
return 0;
|
|
||||||
|
|
||||||
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");
|
av_log(bsfc, AV_LOG_ERROR, "Error parsing ADTS frame header!\n");
|
||||||
return AVERROR_INVALIDDATA;
|
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;
|
in->size -= AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent;
|
||||||
buf_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;
|
in->size -= get_bits_count(&gb)/8;
|
||||||
buf += 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init_put_bits(&pb, avctx->extradata, avctx->extradata_size);
|
extradata = av_mallocz(2 + pce_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
if (!extradata) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
finish:
|
||||||
*poutbuf_size = buf_size;
|
av_packet_move_ref(out, in);
|
||||||
|
av_packet_free(&in);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aac_adtstoasc_init(AVBSFContext *ctx)
|
||||||
|
{
|
||||||
|
av_freep(&ctx->par_out->extradata);
|
||||||
|
ctx->par_out->extradata_size = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVBitStreamFilter ff_aac_adtstoasc_bsf = {
|
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,
|
int (*init)(AVBSFContext *ctx);
|
||||||
AVCodecContext *avctx, const char *args,
|
int (*filter)(AVBSFContext *ctx, AVPacket *pkt);
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
void (*close)(AVBSFContext *ctx);
|
||||||
const uint8_t *buf, int buf_size, int keyframe);
|
|
||||||
void (*close)(AVBitStreamFilterContext *bsfc);
|
|
||||||
struct AVBitStreamFilter *next;
|
|
||||||
} 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)
|
const AVBitStreamFilter *filter = NULL;
|
||||||
return f->next;
|
void *opaque = NULL;
|
||||||
else
|
|
||||||
return first_bitstream_filter;
|
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;
|
AVBitStreamFilterContext *ctx = NULL;
|
||||||
|
BSFCompatContext *priv = NULL;
|
||||||
|
const AVBitStreamFilter *bsf;
|
||||||
|
|
||||||
while (bsf = av_bitstream_filter_next(bsf)) {
|
bsf = av_bsf_get_by_name(name);
|
||||||
if (!strcmp(name, bsf->name)) {
|
if (!bsf)
|
||||||
AVBitStreamFilterContext *bsfc =
|
|
||||||
av_mallocz(sizeof(AVBitStreamFilterContext));
|
|
||||||
if (!bsfc)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
bsfc->filter = bsf;
|
|
||||||
bsfc->priv_data = NULL;
|
ctx = av_mallocz(sizeof(*ctx));
|
||||||
if (bsf->priv_data_size) {
|
if (!ctx)
|
||||||
bsfc->priv_data = av_mallocz(bsf->priv_data_size);
|
|
||||||
if (!bsfc->priv_data) {
|
|
||||||
av_freep(&bsfc);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
priv = av_mallocz(sizeof(*priv));
|
||||||
return bsfc;
|
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;
|
BSFCompatContext *priv = bsfc->priv_data;
|
||||||
*poutbuf_size = buf_size;
|
AVPacket pkt = { 0 };
|
||||||
return bsfc->filter->filter(bsfc, avctx, args ? args : bsfc->args,
|
int ret;
|
||||||
poutbuf, poutbuf_size, buf, buf_size, keyframe);
|
|
||||||
|
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
|
||||||
|
137
libavcodec/bitstream_filters.c
Normal file
137
libavcodec/bitstream_filters.c
Normal file
@ -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;
|
||||||
|
}
|
219
libavcodec/bsf.c
Normal file
219
libavcodec/bsf.c
Normal file
@ -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;
|
||||||
|
}
|
33
libavcodec/bsf.h
Normal file
33
libavcodec/bsf.h
Normal file
@ -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,
|
static int chomp_filter(AVBSFContext *ctx, AVPacket *out)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
while (buf_size > 0 && !buf[buf_size-1])
|
AVPacket *in;
|
||||||
buf_size--;
|
int ret;
|
||||||
|
|
||||||
*poutbuf = (uint8_t*) buf;
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
*poutbuf_size = buf_size;
|
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,
|
static int dca_core_filter(AVBSFContext *ctx, AVPacket *out)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
|
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) {
|
if (core_size > 0 && core_size <= out->size) {
|
||||||
*poutbuf_size = core_size;
|
out->size = core_size;
|
||||||
} else {
|
|
||||||
*poutbuf_size = buf_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVBitStreamFilter ff_dca_core_bsf = {
|
static const enum AVCodecID codec_ids[] = {
|
||||||
.name = "dca_core",
|
AV_CODEC_ID_DTS, AV_CODEC_ID_NONE,
|
||||||
.filter = dca_core,
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
static int dump_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
|
typedef struct DumpExtradataContext {
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
const AVClass *class;
|
||||||
const uint8_t *buf, int buf_size, int keyframe){
|
int freq;
|
||||||
int cmd= args ? *args : 0;
|
} DumpExtradataContext;
|
||||||
/* 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);
|
static int dump_extradata(AVBSFContext *ctx, AVPacket *out)
|
||||||
memcpy((*poutbuf) + avctx->extradata_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
{
|
||||||
return 1;
|
DumpExtradataContext *s = ctx->priv_data;
|
||||||
}
|
AVPacket *in;
|
||||||
}
|
int ret = 0;
|
||||||
return 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVBitStreamFilter ff_dump_extradata_bsf={
|
ret = av_new_packet(out, in->size + ctx->par_in->extradata_size);
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_packet_free(&in);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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",
|
.name = "dump_extra",
|
||||||
|
.priv_data_size = sizeof(DumpExtradataContext),
|
||||||
|
.priv_class = &dump_extradata_class,
|
||||||
.filter = dump_extradata,
|
.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;
|
err = av_grow_packet(out, sps_pps_size + in_size + nal_header_size);
|
||||||
if ((err = av_reallocp(poutbuf,
|
if (err < 0)
|
||||||
*poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
|
|
||||||
*poutbuf_size = 0;
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
if (sps_pps)
|
if (sps_pps)
|
||||||
memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
|
memcpy(out->data + offset, sps_pps, sps_pps_size);
|
||||||
memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_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] =
|
(out->data + offset + sps_pps_size)[0] =
|
||||||
(*poutbuf + offset + sps_pps_size)[1] = 0;
|
(out->data + offset + sps_pps_size)[1] = 0;
|
||||||
(*poutbuf + offset + sps_pps_size)[2] = 1;
|
(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) {
|
if (extradata + 2 + unit_size > ctx->par_in->extradata + ctx->par_in->extradata_size) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, "
|
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_freep(&ctx->par_out->extradata);
|
||||||
av_free(avctx->extradata);
|
ctx->par_out->extradata = out;
|
||||||
avctx->extradata = out;
|
ctx->par_out->extradata_size = total_size;
|
||||||
avctx->extradata_size = total_size;
|
|
||||||
}
|
|
||||||
ctx->spspps_buf = out;
|
|
||||||
ctx->spspps_size = total_size;
|
|
||||||
|
|
||||||
return length_size;
|
return length_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
|
static int h264_mp4toannexb_init(AVBSFContext *ctx)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
H264BSFContext *ctx = bsfc->priv_data;
|
H264BSFContext *s = ctx->priv_data;
|
||||||
int i;
|
int ret;
|
||||||
uint8_t unit_type;
|
|
||||||
int32_t nal_size;
|
/* retrieve sps and pps NAL units from extradata */
|
||||||
uint32_t cumul_size = 0;
|
if (ctx->par_in->extradata_size >= 6) {
|
||||||
const uint8_t *buf_end = buf + buf_size;
|
ret = h264_extradata_to_annexb(ctx, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
int ret = 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/* nothing to filter */
|
|
||||||
if (!avctx->extradata || avctx->extradata_size < 6) {
|
|
||||||
*poutbuf = (uint8_t *)buf;
|
|
||||||
*poutbuf_size = buf_size;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* retrieve sps and pps NAL units from extradata */
|
static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out)
|
||||||
if (!ctx->extradata_parsed) {
|
{
|
||||||
if (args && strstr(args, "private_spspps_buf"))
|
H264BSFContext *s = ctx->priv_data;
|
||||||
ctx->private_spspps = 1;
|
|
||||||
|
|
||||||
ret = h264_extradata_to_annexb(ctx, avctx, AV_INPUT_BUFFER_PADDING_SIZE);
|
AVPacket *in;
|
||||||
|
uint8_t unit_type;
|
||||||
|
int32_t nal_size;
|
||||||
|
uint32_t cumul_size = 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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
ctx->length_size = ret;
|
|
||||||
ctx->new_idr = 1;
|
/* nothing to filter */
|
||||||
ctx->idr_sps_seen = 0;
|
if (!s->extradata_parsed) {
|
||||||
ctx->idr_pps_seen = 0;
|
av_packet_move_ref(out, in);
|
||||||
ctx->extradata_parsed = 1;
|
av_packet_free(&in);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*poutbuf_size = 0;
|
buf = in->data;
|
||||||
*poutbuf = NULL;
|
buf_size = in->size;
|
||||||
|
buf_end = in->data + in->size;
|
||||||
|
|
||||||
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 (!s->idr_sps_seen) {
|
||||||
if (ctx->sps_offset == -1)
|
if (s->sps_offset == -1)
|
||||||
av_log(avctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n");
|
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,
|
if ((ret = alloc_and_copy(out,
|
||||||
ctx->spspps_buf + ctx->sps_offset,
|
ctx->par_out->extradata + s->sps_offset,
|
||||||
ctx->pps_offset != -1 ? ctx->pps_offset : ctx->spspps_size - ctx->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))
|
if (!s->new_idr && unit_type == 5 && (buf[1] & 0x80))
|
||||||
ctx->new_idr = 1;
|
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 (s->new_idr && unit_type == 5 && !s->idr_sps_seen && !s->idr_pps_seen) {
|
||||||
if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
|
if ((ret=alloc_and_copy(out,
|
||||||
ctx->spspps_buf, ctx->spspps_size,
|
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) {
|
} else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) {
|
||||||
if (ctx->pps_offset == -1) {
|
if (s->pps_offset == -1) {
|
||||||
av_log(avctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n");
|
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(poutbuf, poutbuf_size,
|
if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0)
|
||||||
NULL, 0, buf, nal_size)) < 0)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if ((ret = alloc_and_copy(poutbuf, poutbuf_size,
|
} else if ((ret = alloc_and_copy(out,
|
||||||
ctx->spspps_buf + ctx->pps_offset, ctx->spspps_size - ctx->pps_offset,
|
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,
|
if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0)
|
||||||
NULL, 0, buf, nal_size)) < 0)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
if (!ctx->new_idr && unit_type == 1) {
|
if (!s->new_idr && unit_type == 1) {
|
||||||
ctx->new_idr = 1;
|
s->new_idr = 1;
|
||||||
ctx->idr_sps_seen = 0;
|
s->idr_sps_seen = 0;
|
||||||
ctx->idr_pps_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);
|
if (ret < 0)
|
||||||
*poutbuf_size = 0;
|
av_packet_unref(out);
|
||||||
|
av_packet_free(&in);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void h264_mp4toannexb_filter_close(AVBitStreamFilterContext *bsfc)
|
static const enum AVCodecID codec_ids[] = {
|
||||||
{
|
AV_CODEC_ID_H264, AV_CODEC_ID_NONE,
|
||||||
H264BSFContext *ctx = bsfc->priv_data;
|
};
|
||||||
if (ctx->private_spspps)
|
|
||||||
av_freep(&ctx->spspps_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(&ctx->par_out->extradata);
|
||||||
av_freep(&avctx->extradata);
|
ctx->par_out->extradata = new_extradata;
|
||||||
avctx->extradata = new_extradata;
|
ctx->par_out->extradata_size = new_extradata_size;
|
||||||
avctx->extradata_size = new_extradata_size;
|
|
||||||
}
|
|
||||||
ctx->spspps_buf = new_extradata;
|
|
||||||
ctx->spspps_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,
|
static int hevc_mp4toannexb_init(AVBSFContext *ctx)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
HEVCBSFContext *ctx = bsfc->priv_data;
|
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 *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) {
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
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 = hevc_extradata_to_annexb(ctx, avctx);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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;
|
bytestream2_init(&gb, in->data, in->size);
|
||||||
*poutbuf = NULL;
|
|
||||||
|
|
||||||
bytestream2_init(&gb, buf, buf_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 ||
|
if (SIZE_MAX - nalu_size < 4 ||
|
||||||
SIZE_MAX - out_size - 4 < nalu_size ||
|
SIZE_MAX - 4 - nalu_size < extra_size) {
|
||||||
SIZE_MAX - out_size - 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);
|
memcpy(out->data + prev_size, ctx->par_out->extradata, extra_size);
|
||||||
AV_WB32(out + out_size + extra_size, 1);
|
AV_WB32(out->data + prev_size + extra_size, 1);
|
||||||
bytestream2_get_buffer(&gb, out + out_size + 4 + extra_size, nalu_size);
|
bytestream2_get_buffer(&gb, out->data + prev_size + 4 + extra_size, nalu_size);
|
||||||
out_size += 4 + nalu_size + extra_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*poutbuf = out;
|
ret = av_packet_copy_props(out, in);
|
||||||
*poutbuf_size = out_size;
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
return 1;
|
|
||||||
|
|
||||||
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)
|
static const enum AVCodecID codec_ids[] = {
|
||||||
{
|
AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE,
|
||||||
HEVCBSFContext *ctx = bsfc->priv_data;
|
};
|
||||||
if (ctx->private_spspps)
|
|
||||||
av_freep(&ctx->spspps_buf);
|
const AVBitStreamFilter ff_hevc_mp4toannexb_bsf = {
|
||||||
}
|
.name = "hevc_mp4toannexb",
|
||||||
|
.priv_data_size = sizeof(HEVCBSFContext),
|
||||||
AVBitStreamFilter ff_hevc_mp4toannexb_bsf = {
|
.init = hevc_mp4toannexb_init,
|
||||||
"hevc_mp4toannexb",
|
.filter = hevc_mp4toannexb_filter,
|
||||||
sizeof(HEVCBSFContext),
|
.codec_ids = codec_ids,
|
||||||
hevc_mp4toannexb_filter,
|
|
||||||
hevc_mp4toannexb_close,
|
|
||||||
};
|
};
|
||||||
|
@ -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,
|
static int imx_dump_header(AVBSFContext *ctx, AVPacket *out)
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size, int keyframe)
|
|
||||||
{
|
{
|
||||||
/* 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) {
|
AVPacket *in;
|
||||||
av_log(avctx, AV_LOG_ERROR, "imx bitstream filter only applies to mpeg2video codec\n");
|
int ret = 0;
|
||||||
return 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
*poutbuf = av_malloc(buf_size + 20 + AV_INPUT_BUFFER_PADDING_SIZE);
|
static const enum AVCodecID codec_ids[] = {
|
||||||
if (!*poutbuf)
|
AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_NONE,
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
AVBitStreamFilter ff_imx_dump_header_bsf = {
|
const AVBitStreamFilter ff_imx_dump_header_bsf = {
|
||||||
.name = "imxdump",
|
.name = "imxdump",
|
||||||
.filter = imx_dump_header,
|
.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,
|
static int mjpeg2jpeg_filter(AVBSFContext *ctx, AVPacket *out)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
|
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) {
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
av_log(avctx, AV_LOG_ERROR, "input is truncated\n");
|
|
||||||
return AVERROR_INVALIDDATA;
|
if (in->size < 12) {
|
||||||
|
av_log(ctx, AV_LOG_ERROR, "input is truncated\n");
|
||||||
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
if (AV_RB16(buf) != 0xffd8) {
|
if (AV_RB16(in->data) != 0xffd8) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "input is not MJPEG\n");
|
av_log(ctx, AV_LOG_ERROR, "input is not MJPEG\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
if (buf[2] == 0xff && buf[3] == APP0) {
|
if (in->data[2] == 0xff && in->data[3] == APP0) {
|
||||||
input_skip = (buf[4] << 8) + buf[5] + 4;
|
input_skip = (in->data[4] << 8) + in->data[5] + 4;
|
||||||
} else {
|
} else {
|
||||||
input_skip = 2;
|
input_skip = 2;
|
||||||
}
|
}
|
||||||
if (buf_size < input_skip) {
|
if (in->size < input_skip) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "input is truncated\n");
|
av_log(ctx, AV_LOG_ERROR, "input is truncated\n");
|
||||||
return AVERROR_INVALIDDATA;
|
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);
|
ret = av_new_packet(out, output_size);
|
||||||
if (!output)
|
if (ret < 0)
|
||||||
return AVERROR(ENOMEM);
|
goto fail;
|
||||||
out = append(out, jpeg_header, sizeof(jpeg_header));
|
|
||||||
out = append_dht_segment(out);
|
output = out->data;
|
||||||
out = append(out, buf + input_skip, buf_size - input_skip);
|
|
||||||
*poutbuf = output;
|
output = append(output, jpeg_header, sizeof(jpeg_header));
|
||||||
*poutbuf_size = output_size;
|
output = append_dht_segment(output);
|
||||||
return 1;
|
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,
|
static int mjpega_dump_header(AVBSFContext *ctx, AVPacket *out)
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size, int keyframe)
|
|
||||||
{
|
{
|
||||||
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) {
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
av_log(avctx, AV_LOG_ERROR, "mjpega bitstream filter only applies to mjpeg codec\n");
|
if (ret < 0)
|
||||||
return 0;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
*poutbuf_size = 0;
|
ret = av_new_packet(out, in->size + 44);
|
||||||
*poutbuf = av_malloc(buf_size + 44 + AV_INPUT_BUFFER_PADDING_SIZE);
|
if (ret < 0)
|
||||||
if (!*poutbuf)
|
goto fail;
|
||||||
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 */
|
|
||||||
|
|
||||||
for (i = 0; i < buf_size - 1; i++) {
|
ret = av_packet_copy_props(out, in);
|
||||||
if (buf[i] == 0xff) {
|
if (ret < 0)
|
||||||
switch (buf[i + 1]) {
|
goto fail;
|
||||||
|
|
||||||
|
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 < 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(&out_buf, dqt); /* quant off */
|
||||||
bytestream_put_be32(&poutbufp, dht); /* huff off */
|
bytestream_put_be32(&out_buf, dht); /* huff off */
|
||||||
bytestream_put_be32(&poutbufp, sof0); /* image off */
|
bytestream_put_be32(&out_buf, sof0); /* image off */
|
||||||
bytestream_put_be32(&poutbufp, i + 46); /* scan off */
|
bytestream_put_be32(&out_buf, i + 46); /* scan off */
|
||||||
bytestream_put_be32(&poutbufp, i + 46 + AV_RB16(buf + i + 2)); /* data off */
|
bytestream_put_be32(&out_buf, i + 46 + AV_RB16(in->data + i + 2)); /* data off */
|
||||||
bytestream_put_buffer(&poutbufp, buf + 2, buf_size - 2); /* skip already written SOI */
|
bytestream_put_buffer(&out_buf, in->data + 2, in->size - 2); /* skip already written SOI */
|
||||||
*poutbuf_size = poutbufp - *poutbuf;
|
|
||||||
return 1;
|
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")) {
|
if (i + 8 < in->size && AV_RL32(in->data + i + 8) == AV_RL32("mjpg")) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "bitstream already formatted\n");
|
av_log(ctx, AV_LOG_ERROR, "bitstream already formatted\n");
|
||||||
memcpy(*poutbuf, buf, buf_size);
|
av_packet_unref(out);
|
||||||
*poutbuf_size = buf_size;
|
av_packet_move_ref(out, in);
|
||||||
return 1;
|
av_packet_free(&in);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
av_freep(poutbuf);
|
|
||||||
av_log(avctx, AV_LOG_ERROR, "could not find SOS marker in bitstream\n");
|
|
||||||
return 0;
|
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 = {
|
static const enum AVCodecID codec_ids[] = {
|
||||||
|
AV_CODEC_ID_MJPEG, AV_CODEC_ID_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const AVBitStreamFilter ff_mjpega_dump_header_bsf = {
|
||||||
.name = "mjpegadump",
|
.name = "mjpegadump",
|
||||||
.filter = mjpega_dump_header,
|
.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,
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
if (ret < 0)
|
||||||
const uint8_t *buf, int buf_size, int keyframe){
|
return ret;
|
||||||
if (buf_size > 0xffff) return 0;
|
|
||||||
*poutbuf_size = buf_size + 2;
|
if (in->size > 0xffff) {
|
||||||
*poutbuf = av_malloc(*poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
ret = AVERROR_INVALIDDATA;
|
||||||
if (!*poutbuf)
|
goto fail;
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
AV_WB16(*poutbuf, buf_size);
|
|
||||||
memcpy(*poutbuf + 2, buf, buf_size);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AVBitStreamFilter ff_text2movsub_bsf={
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AVBitStreamFilter ff_text2movsub_bsf = {
|
||||||
.name = "text2movsub",
|
.name = "text2movsub",
|
||||||
.filter = text2movsub,
|
.filter = text2movsub,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mov2textsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
|
static int mov2textsub(AVBSFContext *ctx, AVPacket *out)
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
{
|
||||||
const uint8_t *buf, int buf_size, int keyframe){
|
AVPacket *in;
|
||||||
if (buf_size < 2) return 0;
|
int ret = 0;
|
||||||
*poutbuf_size = FFMIN(buf_size - 2, AV_RB16(buf));
|
|
||||||
*poutbuf = av_malloc(*poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
if (!*poutbuf)
|
if (ret < 0)
|
||||||
return AVERROR(ENOMEM);
|
return ret;
|
||||||
memcpy(*poutbuf, buf + 2, *poutbuf_size);
|
|
||||||
return 1;
|
if (in->size < 2) {
|
||||||
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVBitStreamFilter ff_mov2textsub_bsf={
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
static int mp3_header_decompress(AVBSFContext *ctx, AVPacket *out)
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
{
|
||||||
const uint8_t *buf, int buf_size, int keyframe){
|
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;
|
av_packet_move_ref(out, in);
|
||||||
*poutbuf_size= buf_size;
|
av_packet_free(&in);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(avctx->extradata_size != 15 || strcmp(avctx->extradata, "FFCMP3 0.0")){
|
if(ctx->par_in->extradata_size != 15 || strcmp(ctx->par_in->extradata, "FFCMP3 0.0")){
|
||||||
av_log(avctx, AV_LOG_ERROR, "Extradata invalid %d\n", avctx->extradata_size);
|
av_log(ctx, AV_LOG_ERROR, "Extradata invalid %d\n", ctx->par_in->extradata_size);
|
||||||
return -1;
|
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");
|
av_log(ctx, AV_LOG_ERROR, "Could not find bitrate_index.\n");
|
||||||
return -1;
|
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;
|
ret = av_new_packet(out, frame_size);
|
||||||
*poutbuf= av_malloc(frame_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
if (ret < 0)
|
||||||
memcpy(*poutbuf + frame_size - buf_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
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){
|
if(ctx->par_in->channels==2){
|
||||||
uint8_t *p= *poutbuf + frame_size - buf_size;
|
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={
|
static const enum AVCodecID codec_ids[] = {
|
||||||
|
AV_CODEC_ID_MP3, AV_CODEC_ID_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const AVBitStreamFilter ff_mp3_header_decompress_bsf = {
|
||||||
.name = "mp3decomp",
|
.name = "mp3decomp",
|
||||||
.filter = mp3_header_decompress,
|
.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,
|
static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
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) {
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
av_log(avctx, AV_LOG_ERROR,
|
if (ret < 0)
|
||||||
"The mpeg4_unpack_bframes bitstream filter is only useful for mpeg4.\n");
|
return ret;
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ctx->updated_extradata && avctx->extradata) {
|
scan_buffer(in->data, in->size, &pos_p, &nb_vop, &pos_vop2);
|
||||||
int pos_p_ext = -1;
|
av_log(ctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (pos_vop2 >= 0) {
|
if (pos_vop2 >= 0) {
|
||||||
if (ctx->b_frame_buf) {
|
if (s->b_frame_buf) {
|
||||||
av_log(avctx, AV_LOG_WARNING,
|
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);
|
av_freep(&s->b_frame_buf);
|
||||||
ctx->b_frame_buf_size = 0;
|
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;
|
s->b_frame_buf_size = in->size - pos_vop2;
|
||||||
ctx->b_frame_buf = create_new_buffer(buf + pos_vop2, ctx->b_frame_buf_size);
|
s->b_frame_buf = create_new_buffer(in->data + pos_vop2, s->b_frame_buf_size);
|
||||||
if (!ctx->b_frame_buf) {
|
if (!s->b_frame_buf) {
|
||||||
ctx->b_frame_buf_size = 0;
|
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;
|
av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size);
|
||||||
*poutbuf_size = ctx->b_frame_buf_size;
|
if (in->size <= MAX_NVOP_SIZE) {
|
||||||
/* the output buffer is distinct from the input buffer */
|
|
||||||
ret = 1;
|
|
||||||
if (buf_size <= MAX_NVOP_SIZE) {
|
|
||||||
/* N-VOP */
|
/* N-VOP */
|
||||||
av_log(avctx, AV_LOG_DEBUG, "Skipping N-VOP.\n");
|
av_log(ctx, AV_LOG_DEBUG, "Skipping N-VOP.\n");
|
||||||
ctx->b_frame_buf = NULL;
|
s->b_frame_buf = NULL;
|
||||||
ctx->b_frame_buf_size = 0;
|
s->b_frame_buf_size = 0;
|
||||||
} else {
|
} else {
|
||||||
/* copy packet into BSFContext */
|
/* copy packet into BSFContext */
|
||||||
ctx->b_frame_buf_size = buf_size;
|
s->b_frame_buf_size = in->size;
|
||||||
ctx->b_frame_buf = create_new_buffer(buf , buf_size);
|
s->b_frame_buf = create_new_buffer(in->data, in->size);
|
||||||
if (!ctx->b_frame_buf) {
|
if (!s->b_frame_buf) {
|
||||||
ctx->b_frame_buf_size = 0;
|
s->b_frame_buf_size = 0;
|
||||||
av_freep(poutbuf);
|
av_packet_unref(out);
|
||||||
*poutbuf_size = 0;
|
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;
|
av_packet_move_ref(out, in);
|
||||||
*poutbuf_size = pos_vop2;
|
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");
|
av_log(ctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n");
|
||||||
*poutbuf_size = buf_size;
|
av_packet_move_ref(out, in);
|
||||||
*poutbuf = create_new_buffer(buf, buf_size);
|
|
||||||
if (!*poutbuf) {
|
|
||||||
*poutbuf_size = 0;
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
}
|
|
||||||
/* 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';
|
out->data[pos_p] = '\0';
|
||||||
/* the output buffer is distinct from the input buffer */
|
|
||||||
ret = 1;
|
|
||||||
} else {
|
} else {
|
||||||
/* copy packet */
|
/* copy packet */
|
||||||
*poutbuf = (uint8_t *) buf;
|
av_packet_move_ref(out, in);
|
||||||
*poutbuf_size = buf_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
av_packet_free(&in);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mpeg4_unpack_bframes_close(AVBitStreamFilterContext *bsfc)
|
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 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
static int noise(AVBSFContext *ctx, AVPacket *out)
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
{
|
||||||
const uint8_t *buf, int buf_size, int keyframe){
|
NoiseContext *s = ctx->priv_data;
|
||||||
unsigned int *state= bsfc->priv_data;
|
AVPacket *in;
|
||||||
int amount= args ? atoi(args) : (*state % 10001+1);
|
int amount = s->amount > 0 ? s->amount : (s->state % 10001 + 1);
|
||||||
int i;
|
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);
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
if (!*poutbuf)
|
if (ret < 0)
|
||||||
return AVERROR(ENOMEM);
|
return ret;
|
||||||
|
|
||||||
memcpy(*poutbuf, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
ret = av_new_packet(out, in->size);
|
||||||
for(i=0; i<buf_size; i++){
|
if (ret < 0)
|
||||||
(*state) += (*poutbuf)[i] + 1;
|
goto fail;
|
||||||
if(*state % amount == 0)
|
|
||||||
(*poutbuf)[i] = *state;
|
ret = av_packet_copy_props(out, in);
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
memcpy(out->data, in->data, in->size);
|
||||||
|
|
||||||
|
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,
|
typedef struct RemoveExtradataContext {
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
const AVClass *class;
|
||||||
const uint8_t *buf, int buf_size, int keyframe){
|
int freq;
|
||||||
int cmd= args ? *args : 0;
|
|
||||||
AVCodecParserContext *s;
|
|
||||||
|
|
||||||
if(!bsfc->parser){
|
AVCodecParserContext *parser;
|
||||||
bsfc->parser= av_parser_init(avctx->codec_id);
|
AVCodecContext *avctx;
|
||||||
}
|
} RemoveExtradataContext;
|
||||||
s= bsfc->parser;
|
|
||||||
|
|
||||||
if(s && s->parser->split){
|
static int remove_extradata(AVBSFContext *ctx, AVPacket *out)
|
||||||
if( (((avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ||
|
{
|
||||||
(avctx->flags2 & AV_CODEC_FLAG2_LOCAL_HEADER)) && cmd == 'a')
|
RemoveExtradataContext *s = ctx->priv_data;
|
||||||
||(!keyframe && cmd=='k')
|
|
||||||
||(cmd=='e' || !cmd)
|
AVPacket *in;
|
||||||
){
|
int ret;
|
||||||
int i= s->parser->split(avctx, buf, buf_size);
|
|
||||||
buf += i;
|
ret = ff_bsf_get_packet(ctx, &in);
|
||||||
buf_size -= i;
|
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={
|
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",
|
.name = "remove_extra",
|
||||||
|
.priv_data_size = sizeof(RemoveExtradataContext),
|
||||||
|
.priv_class = &remove_extradata_class,
|
||||||
|
.init = remove_extradata_init,
|
||||||
|
.close = remove_extradata_close,
|
||||||
.filter = remove_extradata,
|
.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_MINOR 35
|
||||||
#define LIBAVCODEC_VERSION_MICRO 102
|
#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,
|
static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out)
|
||||||
uint8_t **poutbuf, int *poutbuf_size)
|
|
||||||
{
|
{
|
||||||
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;
|
sz = sum + 2 + (mag + 1) * n_in;
|
||||||
ptr = *poutbuf = av_malloc(sz);
|
res = av_new_packet(out, sz);
|
||||||
if (!ptr)
|
if (res < 0)
|
||||||
return AVERROR(ENOMEM);
|
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,
|
static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out)
|
||||||
AVCodecContext *avctx, const char *args,
|
|
||||||
uint8_t **poutbuf, int *poutbuf_size,
|
|
||||||
const uint8_t *buf, int buf_size,
|
|
||||||
int keyframe)
|
|
||||||
{
|
{
|
||||||
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)
|
if ((res = init_get_bits8(&gb, in->data, in->size)) < 0)
|
||||||
return res;
|
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) {
|
if (uses_superframe_syntax && s->n_cache > 0) {
|
||||||
av_log(avctx, AV_LOG_ERROR,
|
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;
|
res = AVERROR_INVALIDDATA;
|
||||||
} else if ((!invisible || uses_superframe_syntax) && !ctx->n_cache) {
|
goto done;
|
||||||
|
} else if ((!invisible || uses_superframe_syntax) && !s->n_cache) {
|
||||||
// passthrough
|
// passthrough
|
||||||
*poutbuf = (uint8_t *) buf;
|
av_packet_move_ref(out, in);
|
||||||
*poutbuf_size = buf_size;
|
goto done;
|
||||||
return 0;
|
} else if (s->n_cache + 1 >= MAX_CACHE) {
|
||||||
} else if (ctx->n_cache + 1 >= MAX_CACHE) {
|
av_log(ctx, AV_LOG_ERROR,
|
||||||
av_log(avctx, 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);
|
s->cache[s->n_cache].data = av_malloc(in->size);
|
||||||
if (!ctx->cache[ctx->n_cache].data)
|
if (!s->cache[s->n_cache].data) {
|
||||||
return AVERROR(ENOMEM);
|
res = AVERROR(ENOMEM);
|
||||||
memcpy(ctx->cache[ctx->n_cache++].data, buf, buf_size);
|
goto done;
|
||||||
*poutbuf = NULL;
|
|
||||||
*poutbuf_size = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
av_assert0(ctx->n_cache > 0);
|
memcpy(s->cache[s->n_cache++].data, in->data, in->size);
|
||||||
|
res = AVERROR(EAGAIN);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
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,
|
if ((res = merge_superframe(s->cache, s->n_cache + 1, out)) < 0)
|
||||||
poutbuf, poutbuf_size)) < 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;
|
return res;
|
||||||
|
|
||||||
for (n = 0; n < ctx->n_cache; n++)
|
|
||||||
av_freep(&ctx->cache[n].data);
|
|
||||||
ctx->n_cache = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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++)
|
for (n = 0; n < s->n_cache; n++)
|
||||||
av_freep(&ctx->cache[n].data);
|
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user