FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
h264_mp4toannexb_bsf.c
Go to the documentation of this file.
1 /*
2  * H.264 MP4 to Annex B byte stream format filter
3  * Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
4  *
5  * This file is part of FFmpeg.
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #include <string.h>
23 
24 #include "libavutil/intreadwrite.h"
25 #include "libavutil/mem.h"
26 #include "avcodec.h"
27 
28 typedef struct H264BSFContext {
34 
35 static int alloc_and_copy(uint8_t **poutbuf, int *poutbuf_size,
36  const uint8_t *sps_pps, uint32_t sps_pps_size,
37  const uint8_t *in, uint32_t in_size)
38 {
39  uint32_t offset = *poutbuf_size;
40  uint8_t nal_header_size = offset ? 3 : 4;
41  int err;
42 
43  *poutbuf_size += sps_pps_size + in_size + nal_header_size;
44  if ((err = av_reallocp(poutbuf,
45  *poutbuf_size + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) {
46  *poutbuf_size = 0;
47  return err;
48  }
49  if (sps_pps)
50  memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
51  memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
52  if (!offset) {
53  AV_WB32(*poutbuf + sps_pps_size, 1);
54  } else {
55  (*poutbuf + offset + sps_pps_size)[0] =
56  (*poutbuf + offset + sps_pps_size)[1] = 0;
57  (*poutbuf + offset + sps_pps_size)[2] = 1;
58  }
59 
60  return 0;
61 }
62 
63 static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding)
64 {
65  uint16_t unit_size;
66  uint64_t total_size = 0;
67  uint8_t *out = NULL, unit_nb, sps_done = 0,
68  sps_seen = 0, pps_seen = 0;
69  const uint8_t *extradata = avctx->extradata + 4;
70  static const uint8_t nalu_header[4] = { 0, 0, 0, 1 };
71  int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size
72 
73  /* retrieve sps and pps unit(s) */
74  unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
75  if (!unit_nb) {
76  goto pps;
77  } else {
78  sps_seen = 1;
79  }
80 
81  while (unit_nb--) {
82  int err;
83 
84  unit_size = AV_RB16(extradata);
85  total_size += unit_size + 4;
86  if (total_size > INT_MAX - padding) {
87  av_log(avctx, AV_LOG_ERROR,
88  "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n");
89  av_free(out);
90  return AVERROR(EINVAL);
91  }
92  if (extradata + 2 + unit_size > avctx->extradata + avctx->extradata_size) {
93  av_log(avctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, "
94  "corrupted stream or invalid MP4/AVCC bitstream\n");
95  av_free(out);
96  return AVERROR(EINVAL);
97  }
98  if ((err = av_reallocp(&out, total_size + padding)) < 0)
99  return err;
100  memcpy(out + total_size - unit_size - 4, nalu_header, 4);
101  memcpy(out + total_size - unit_size, extradata + 2, unit_size);
102  extradata += 2 + unit_size;
103 pps:
104  if (!unit_nb && !sps_done++) {
105  unit_nb = *extradata++; /* number of pps unit(s) */
106  if (unit_nb)
107  pps_seen = 1;
108  }
109  }
110 
111  if (out)
112  memset(out + total_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
113 
114  if (!sps_seen)
115  av_log(avctx, AV_LOG_WARNING,
116  "Warning: SPS NALU missing or invalid. "
117  "The resulting stream may not play.\n");
118 
119  if (!pps_seen)
120  av_log(avctx, AV_LOG_WARNING,
121  "Warning: PPS NALU missing or invalid. "
122  "The resulting stream may not play.\n");
123 
124  av_free(avctx->extradata);
125  avctx->extradata = out;
126  avctx->extradata_size = total_size;
127 
128  return length_size;
129 }
130 
132  AVCodecContext *avctx, const char *args,
133  uint8_t **poutbuf, int *poutbuf_size,
134  const uint8_t *buf, int buf_size,
135  int keyframe)
136 {
137  H264BSFContext *ctx = bsfc->priv_data;
138  int i;
139  uint8_t unit_type;
140  int32_t nal_size;
141  uint32_t cumul_size = 0;
142  const uint8_t *buf_end = buf + buf_size;
143  int ret = 0;
144 
145  /* nothing to filter */
146  if (!avctx->extradata || avctx->extradata_size < 6) {
147  *poutbuf = (uint8_t *)buf;
148  *poutbuf_size = buf_size;
149  return 0;
150  }
151 
152  /* retrieve sps and pps NAL units from extradata */
153  if (!ctx->extradata_parsed) {
155  if (ret < 0)
156  return ret;
157  ctx->length_size = ret;
158  ctx->new_idr = 1;
159  ctx->idr_sps_pps_seen = 0;
160  ctx->extradata_parsed = 1;
161  }
162 
163  *poutbuf_size = 0;
164  *poutbuf = NULL;
165  do {
166  ret= AVERROR(EINVAL);
167  if (buf + ctx->length_size > buf_end)
168  goto fail;
169 
170  for (nal_size = 0, i = 0; i<ctx->length_size; i++)
171  nal_size = (nal_size << 8) | buf[i];
172 
173  buf += ctx->length_size;
174  unit_type = *buf & 0x1f;
175 
176  if (buf + nal_size > buf_end || nal_size < 0)
177  goto fail;
178 
179  if (unit_type == 7 || unit_type == 8)
180  ctx->idr_sps_pps_seen = 1;
181 
182  /* if this is a new IDR picture following an IDR picture, reset the idr flag.
183  * Just check first_mb_in_slice to be 0 as this is the simplest solution.
184  * This could be checking idr_pic_id instead, but would complexify the parsing. */
185  if (!ctx->new_idr && unit_type == 5 && (buf[1] & 0x80))
186  ctx->new_idr = 1;
187 
188  /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */
189  if (ctx->new_idr && unit_type == 5 && !ctx->idr_sps_pps_seen) {
190  if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
191  avctx->extradata, avctx->extradata_size,
192  buf, nal_size)) < 0)
193  goto fail;
194  ctx->new_idr = 0;
195  } else {
196  if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
197  NULL, 0, buf, nal_size)) < 0)
198  goto fail;
199  if (!ctx->new_idr && unit_type == 1) {
200  ctx->new_idr = 1;
201  ctx->idr_sps_pps_seen = 0;
202  }
203  }
204 
205  buf += nal_size;
206  cumul_size += nal_size + ctx->length_size;
207  } while (cumul_size < buf_size);
208 
209  return 1;
210 
211 fail:
212  av_freep(poutbuf);
213  *poutbuf_size = 0;
214  return ret;
215 }
216 
218  .name = "h264_mp4toannexb",
219  .priv_data_size = sizeof(H264BSFContext),
221 };