[FFmpeg-devel] [PATCH] h264 bitstream filter
Måns Rullgård
mans
Fri Aug 31 10:15:16 CEST 2007
Benoit Fouet <benoit.fouet at purplelabs.com> writes:
> Michael Niedermayer wrote:
>> Hi
>>
>> On Thu, Aug 30, 2007 at 05:12:09PM +0200, Benoit Fouet wrote:
>> [...]
>>
>>> updated patch attached
>>>
>> [...]
>>
>>> + bsfc->priv_data = out;
>>> + bsfc->filter->priv_data_size = priv_data_size;
>>>
>>
>> bsfc->filter is shared between all instances
>> writing to it is absolutely not allowed
>>
>> please properly initalize priv_data_size to the size of your context
>> and store whatever you need in this context
>>
>>
>
> it's always easier after some sleep :)
> here it is, along with other modifications i thought of...
>
> Index: libavcodec/Makefile
> ===================================================================
> --- libavcodec/Makefile (revision 10260)
> +++ libavcodec/Makefile (working copy)
> @@ -326,6 +326,7 @@
> OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o mpegaudiodata.o
> OBJS-$(CONFIG_MJPEGA_DUMP_HEADER_BSF) += mjpega_dump_header_bsf.o
> OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += imx_dump_header_bsf.o
> +OBJS-$(CONFIG_MP4_AVC_TO_AVC_ES_BSF) += mp4_avc_to_avc_es_bsf.o
Diego sorted these so you'll need to update this.
> OBJS-$(HAVE_PTHREADS) += pthread.o
> OBJS-$(HAVE_W32THREADS) += w32thread.o
> Index: libavcodec/allcodecs.c
> ===================================================================
> --- libavcodec/allcodecs.c (revision 10260)
> +++ libavcodec/allcodecs.c (working copy)
> @@ -284,5 +284,6 @@
> REGISTER_BSF (MP3_HEADER_DECOMPRESS, mp3_header_decompress);
> REGISTER_BSF (MJPEGA_DUMP_HEADER, mjpega_dump_header);
> REGISTER_BSF (IMX_DUMP_HEADER, imx_dump_header);
> + REGISTER_BSF (MP4_AVC_TO_AVC_ES, mp4_avc_to_avc_es);
> }
Ditto.
> Index: libavcodec/allcodecs.h
> ===================================================================
> --- libavcodec/allcodecs.h (revision 10260)
> +++ libavcodec/allcodecs.h (working copy)
> @@ -313,5 +313,6 @@
> extern AVBitStreamFilter mp3_header_decompress_bsf;
> extern AVBitStreamFilter mjpega_dump_header_bsf;
> extern AVBitStreamFilter imx_dump_header_bsf;
> +extern AVBitStreamFilter mp4_avc_to_avc_es_bsf;
Ditto.
> +static void alloc_and_copy( uint8_t **poutbuf, int *poutbuf_size,
> + const uint8_t *in1, uint32_t in1_size,
> + const uint8_t *in2, uint32_t in2_size,
> + uint32_t nal_offset) {
> + *poutbuf = av_malloc(in1_size+in2_size);
> + *poutbuf_size = in1_size+in2_size;
> + memcpy(*poutbuf, in1, in1_size);
> + if (in2)
> + memcpy(*poutbuf+in1_size, in2, in2_size);
> + (*poutbuf)[nal_offset ] = 0;
> + (*poutbuf)[nal_offset+1] = 0;
> + (*poutbuf)[nal_offset+2] = 0;
> + (*poutbuf)[nal_offset+3] = 1;
Maybe use AV_WB32 there.
> +}
> +
> +static int mp4_avc_to_avc_es( AVBitStreamFilterContext *bsfc,
> + AVCodecContext *avctx, const char *args,
> + uint8_t **poutbuf, int *poutbuf_size,
> + const uint8_t *buf, int buf_size,
> + int keyframe ) {
> + /* nothing to filter */
> + if (!avctx->extradata || buf_size < 5 || avctx->extradata_size < 9) {
> + *poutbuf = (uint8_t*) buf;
> + *poutbuf_size = buf_size;
> + return 0;
> + }
> +
> + else {
No need for the else when you return in the if. Save yourself a level
of indentation.
> + AVCBSFContext *ctx = bsfc->priv_data;
> + uint8_t unit_type = buf[4] & 0x1f;
> +
> + if (!ctx->sps_pps_data) {
> + uint16_t unit_size;
> + uint32_t total_size = 0;
> + uint8_t *out = NULL, unit_nb, sps_done = 0;
> + /* skip everything before number of sps units */
> + const uint8_t *extradata = avctx->extradata+5;
> + static const uint8_t nalu_header[4] = {0, 0, 0, 1};
> +
> + /* retrieve sps and pps unit(s) */
> + unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
> + if (!unit_nb) {
> + unit_nb = *extradata++; /* number of pps unit(s) */
> + sps_done++;
> + }
> + while (unit_nb--) {
> + unit_size = AV_RB16(extradata);
> + total_size += unit_size+4;
> + if (extradata+2+unit_size > avctx->extradata+avctx->extradata_size) {
> + av_free(out);
> + return -1;
> + }
> + out = av_realloc(out, total_size);
> + memcpy(out+total_size-unit_size-4, nalu_header, 4);
> + memcpy(out+total_size-unit_size, extradata+2, unit_size);
> + extradata += 2+unit_size;
> +
> + if (!unit_nb && !sps_done++)
> + unit_nb = *extradata++; /* number of pps unit(s) */
> + }
> +
> + ctx->sps_pps_data = out;
> + ctx->size = total_size;
> + }
> +
> + if (unit_type == 5 /* IDR picture */)
> + /* sps and pps have to be prepended to NAL unit */
> + alloc_and_copy(poutbuf, poutbuf_size,
> + ctx->sps_pps_data, ctx->size,
> + buf, buf_size,
> + ctx->size);
> + else if (unit_type == 6 /* SEI */ || unit_type == 9 /* AUD */)
> + /* sps and pps have to be appended to NAL unit */
> + alloc_and_copy(poutbuf, poutbuf_size,
> + buf, buf_size,
> + ctx->sps_pps_data, ctx->size,
> + 0);
This is wrong. Maybe you misunderstood what I said about where to
insert SPS and PPS. They should be added before the first type 5 NAL
unit of an IDR picture, after whatever SEI or AUD units that picture
has. A multislice IDR picture only needs SPS and PPS before the first
slice, and non-IDR pictures should not have SPS or PPS added.
> + else
> + alloc_and_copy(poutbuf, poutbuf_size,
> + buf, buf_size,
> + NULL, 0,
> + 0);
> + }
> +
> + return 1;
> +}
> +
> +AVBitStreamFilter mp4_avc_to_avc_es_bsf = {
> + "mp4_avc_to_avc_es",
I don't like that name.
> + sizeof( AVCBSFContext ),
I'm allergic to spaces inside parenthesis.
> + mp4_avc_to_avc_es,
> +};
> +
--
M?ns Rullg?rd
mans at mansr.com
More information about the ffmpeg-devel
mailing list