2 * H.264 MP4 to Annex B byte stream format filter
3 * Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/intreadwrite.h"
25 #include "libavutil/mem.h"
28 typedef struct H264BSFContext
{
38 static int alloc_and_copy(uint8_t **poutbuf
, int *poutbuf_size
,
39 const uint8_t *sps_pps
, uint32_t sps_pps_size
,
40 const uint8_t *in
, uint32_t in_size
)
42 uint32_t offset
= *poutbuf_size
;
43 uint8_t nal_header_size
= offset
? 3 : 4;
46 *poutbuf_size
+= sps_pps_size
+ in_size
+ nal_header_size
;
47 if ((err
= av_reallocp(poutbuf
,
48 *poutbuf_size
+ FF_INPUT_BUFFER_PADDING_SIZE
)) < 0) {
53 memcpy(*poutbuf
+ offset
, sps_pps
, sps_pps_size
);
54 memcpy(*poutbuf
+ sps_pps_size
+ nal_header_size
+ offset
, in
, in_size
);
56 AV_WB32(*poutbuf
+ sps_pps_size
, 1);
58 (*poutbuf
+ offset
+ sps_pps_size
)[0] =
59 (*poutbuf
+ offset
+ sps_pps_size
)[1] = 0;
60 (*poutbuf
+ offset
+ sps_pps_size
)[2] = 1;
66 static int h264_extradata_to_annexb(H264BSFContext
*ctx
, AVCodecContext
*avctx
, const int padding
)
69 uint64_t total_size
= 0;
70 uint8_t *out
= NULL
, unit_nb
, sps_done
= 0,
71 sps_seen
= 0, pps_seen
= 0;
72 const uint8_t *extradata
= avctx
->extradata
+ 4;
73 static const uint8_t nalu_header
[4] = { 0, 0, 0, 1 };
74 int length_size
= (*extradata
++ & 0x3) + 1; // retrieve length coded size
76 ctx
->sps_offset
= ctx
->pps_offset
= -1;
78 /* retrieve sps and pps unit(s) */
79 unit_nb
= *extradata
++ & 0x1f; /* number of sps unit(s) */
90 unit_size
= AV_RB16(extradata
);
91 total_size
+= unit_size
+ 4;
92 if (total_size
> INT_MAX
- padding
) {
93 av_log(avctx
, AV_LOG_ERROR
,
94 "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n");
96 return AVERROR(EINVAL
);
98 if (extradata
+ 2 + unit_size
> avctx
->extradata
+ avctx
->extradata_size
) {
99 av_log(avctx
, AV_LOG_ERROR
, "Packet header is not contained in global extradata, "
100 "corrupted stream or invalid MP4/AVCC bitstream\n");
102 return AVERROR(EINVAL
);
104 if ((err
= av_reallocp(&out
, total_size
+ padding
)) < 0)
106 memcpy(out
+ total_size
- unit_size
- 4, nalu_header
, 4);
107 memcpy(out
+ total_size
- unit_size
, extradata
+ 2, unit_size
);
108 extradata
+= 2 + unit_size
;
110 if (!unit_nb
&& !sps_done
++) {
111 unit_nb
= *extradata
++; /* number of pps unit(s) */
113 ctx
->pps_offset
= (extradata
- 1) - (avctx
->extradata
+ 4);
120 memset(out
+ total_size
, 0, padding
);
123 av_log(avctx
, AV_LOG_WARNING
,
124 "Warning: SPS NALU missing or invalid. "
125 "The resulting stream may not play.\n");
128 av_log(avctx
, AV_LOG_WARNING
,
129 "Warning: PPS NALU missing or invalid. "
130 "The resulting stream may not play.\n");
132 av_free(avctx
->extradata
);
133 avctx
->extradata
= out
;
134 avctx
->extradata_size
= total_size
;
139 static int h264_mp4toannexb_filter(AVBitStreamFilterContext
*bsfc
,
140 AVCodecContext
*avctx
, const char *args
,
141 uint8_t **poutbuf
, int *poutbuf_size
,
142 const uint8_t *buf
, int buf_size
,
145 H264BSFContext
*ctx
= bsfc
->priv_data
;
149 uint32_t cumul_size
= 0;
150 const uint8_t *buf_end
= buf
+ buf_size
;
153 /* nothing to filter */
154 if (!avctx
->extradata
|| avctx
->extradata_size
< 6) {
155 *poutbuf
= (uint8_t *)buf
;
156 *poutbuf_size
= buf_size
;
160 /* retrieve sps and pps NAL units from extradata */
161 if (!ctx
->extradata_parsed
) {
162 ret
= h264_extradata_to_annexb(ctx
, avctx
, FF_INPUT_BUFFER_PADDING_SIZE
);
165 ctx
->length_size
= ret
;
167 ctx
->idr_sps_seen
= 0;
168 ctx
->idr_pps_seen
= 0;
169 ctx
->extradata_parsed
= 1;
175 ret
= AVERROR(EINVAL
);
176 if (buf
+ ctx
->length_size
> buf_end
)
179 for (nal_size
= 0, i
= 0; i
<ctx
->length_size
; i
++)
180 nal_size
= (nal_size
<< 8) | buf
[i
];
182 buf
+= ctx
->length_size
;
183 unit_type
= *buf
& 0x1f;
185 if (buf
+ nal_size
> buf_end
|| nal_size
< 0)
189 ctx
->idr_sps_seen
= ctx
->new_idr
= 1;
190 else if (unit_type
== 8) {
191 ctx
->idr_pps_seen
= ctx
->new_idr
= 1;
192 /* if SPS has not been seen yet, prepend the AVCC one to PPS */
193 if (!ctx
->idr_sps_seen
) {
194 if (ctx
->sps_offset
== -1)
195 av_log(avctx
, AV_LOG_WARNING
, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n");
197 if ((ret
= alloc_and_copy(poutbuf
, poutbuf_size
,
198 avctx
->extradata
+ ctx
->sps_offset
,
199 ctx
->pps_offset
!= -1 ? ctx
->pps_offset
: avctx
->extradata_size
- ctx
->sps_offset
,
202 ctx
->idr_sps_seen
= 1;
208 /* if this is a new IDR picture following an IDR picture, reset the idr flag.
209 * Just check first_mb_in_slice to be 0 as this is the simplest solution.
210 * This could be checking idr_pic_id instead, but would complexify the parsing. */
211 if (!ctx
->new_idr
&& unit_type
== 5 && (buf
[1] & 0x80))
214 /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */
215 if (ctx
->new_idr
&& unit_type
== 5 && !ctx
->idr_sps_seen
&& !ctx
->idr_pps_seen
) {
216 if ((ret
=alloc_and_copy(poutbuf
, poutbuf_size
,
217 avctx
->extradata
, avctx
->extradata_size
,
221 /* if only SPS has been seen, also insert PPS */
222 } else if (ctx
->new_idr
&& unit_type
== 5 && ctx
->idr_sps_seen
&& !ctx
->idr_pps_seen
) {
223 if (ctx
->pps_offset
== -1) {
224 av_log(avctx
, AV_LOG_WARNING
, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n");
225 if ((ret
= alloc_and_copy(poutbuf
, poutbuf_size
,
226 NULL
, 0, buf
, nal_size
)) < 0)
228 } else if ((ret
= alloc_and_copy(poutbuf
, poutbuf_size
,
229 avctx
->extradata
+ ctx
->pps_offset
, avctx
->extradata_size
- ctx
->pps_offset
,
233 if ((ret
=alloc_and_copy(poutbuf
, poutbuf_size
,
234 NULL
, 0, buf
, nal_size
)) < 0)
236 if (!ctx
->new_idr
&& unit_type
== 1) {
238 ctx
->idr_sps_seen
= 0;
239 ctx
->idr_pps_seen
= 0;
245 cumul_size
+= nal_size
+ ctx
->length_size
;
246 } while (cumul_size
< buf_size
);
256 AVBitStreamFilter ff_h264_mp4toannexb_bsf
= {
257 .name
= "h264_mp4toannexb",
258 .priv_data_size
= sizeof(H264BSFContext
),
259 .filter
= h264_mp4toannexb_filter
,