annotate h264_mp4toannexb_bsf.c @ 8991:ca768cb2bfb6 libavcodec

Use last decoded SPS as current SPS in order to parse picture timing SEI correctly. This works around an apparent H.264 standard deficiency. Patch by Ivan Schreter, schreter gmx net
author cehoyos
date Fri, 20 Feb 2009 16:20:01 +0000
parents 2acf0ae7b041
children 31a033fae70e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5644
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
1 /*
8156
a5e7dbce5412 Change email address to a valid one.
benoit
parents: 6134
diff changeset
2 * Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
5644
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
3 *
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
4 * This file is part of FFmpeg.
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
5 *
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
6 * FFmpeg is free software; you can redistribute it and/or
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
7 * modify it under the terms of the GNU Lesser General Public
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
8 * License as published by the Free Software Foundation; either
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
9 * version 2.1 of the License, or (at your option) any later version.
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
10 *
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
11 * FFmpeg is distributed in the hope that it will be useful,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
14 * Lesser General Public License for more details.
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
15 *
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
16 * You should have received a copy of the GNU Lesser General Public
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
17 * License along with FFmpeg; if not, write to the Free Software
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
19 */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
20
8573
2acf0ae7b041 Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents: 8156
diff changeset
21 #include "libavutil/intreadwrite.h"
5644
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
22 #include "avcodec.h"
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
23
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
24 typedef struct H264BSFContext {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
25 uint8_t length_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
26 uint8_t first_idr;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
27 uint8_t *sps_pps_data;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
28 uint32_t size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
29 } H264BSFContext;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
30
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
31 static void alloc_and_copy(uint8_t **poutbuf, int *poutbuf_size,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
32 const uint8_t *sps_pps, uint32_t sps_pps_size,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
33 const uint8_t *in, uint32_t in_size) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
34 uint32_t offset = *poutbuf_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
35 uint8_t nal_header_size = offset ? 3 : 4;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
36
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
37 *poutbuf_size += sps_pps_size+in_size+nal_header_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
38 *poutbuf = av_realloc(*poutbuf, *poutbuf_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
39 if (sps_pps)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
40 memcpy(*poutbuf+offset, sps_pps, sps_pps_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
41 memcpy(*poutbuf+sps_pps_size+nal_header_size+offset, in, in_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
42 if (!offset)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
43 AV_WB32(*poutbuf+sps_pps_size, 1);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
44 else {
6134
6d0c5a68d559 Fix a bug causing the generated stream to be corrupt if the buffer
andoma
parents: 5644
diff changeset
45 (*poutbuf+offset+sps_pps_size)[0] = (*poutbuf+offset+sps_pps_size)[1] = 0;
6d0c5a68d559 Fix a bug causing the generated stream to be corrupt if the buffer
andoma
parents: 5644
diff changeset
46 (*poutbuf+offset+sps_pps_size)[2] = 1;
5644
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
47 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
48 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
49
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
50 static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
51 AVCodecContext *avctx, const char *args,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
52 uint8_t **poutbuf, int *poutbuf_size,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
53 const uint8_t *buf, int buf_size,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
54 int keyframe) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
55 H264BSFContext *ctx = bsfc->priv_data;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
56 uint8_t unit_type;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
57 uint32_t nal_size, cumul_size = 0;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
58
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
59 /* nothing to filter */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
60 if (!avctx->extradata || avctx->extradata_size < 6) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
61 *poutbuf = (uint8_t*) buf;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
62 *poutbuf_size = buf_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
63 return 0;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
64 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
65
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
66 /* retrieve sps and pps NAL units from extradata */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
67 if (!ctx->sps_pps_data) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
68 uint16_t unit_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
69 uint32_t total_size = 0;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
70 uint8_t *out = NULL, unit_nb, sps_done = 0;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
71 const uint8_t *extradata = avctx->extradata+4;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
72 static const uint8_t nalu_header[4] = {0, 0, 0, 1};
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
73
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
74 /* retrieve length coded size */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
75 ctx->length_size = (*extradata++ & 0x3) + 1;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
76 if (ctx->length_size == 3)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
77 return AVERROR(EINVAL);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
78
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
79 /* retrieve sps and pps unit(s) */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
80 unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
81 if (!unit_nb) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
82 unit_nb = *extradata++; /* number of pps unit(s) */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
83 sps_done++;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
84 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
85 while (unit_nb--) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
86 unit_size = AV_RB16(extradata);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
87 total_size += unit_size+4;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
88 if (extradata+2+unit_size > avctx->extradata+avctx->extradata_size) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
89 av_free(out);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
90 return AVERROR(EINVAL);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
91 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
92 out = av_realloc(out, total_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
93 if (!out)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
94 return AVERROR(ENOMEM);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
95 memcpy(out+total_size-unit_size-4, nalu_header, 4);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
96 memcpy(out+total_size-unit_size, extradata+2, unit_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
97 extradata += 2+unit_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
98
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
99 if (!unit_nb && !sps_done++)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
100 unit_nb = *extradata++; /* number of pps unit(s) */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
101 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
102
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
103 ctx->sps_pps_data = out;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
104 ctx->size = total_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
105 ctx->first_idr = 1;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
106 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
107
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
108 *poutbuf_size = 0;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
109 *poutbuf = NULL;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
110 do {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
111 if (ctx->length_size == 1)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
112 nal_size = buf[0];
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
113 else if (ctx->length_size == 2)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
114 nal_size = AV_RB16(buf);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
115 else
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
116 nal_size = AV_RB32(buf);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
117
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
118 buf += ctx->length_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
119 unit_type = *buf & 0x1f;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
120
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
121 /* prepend only to the first type 5 NAL unit of an IDR picture */
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
122 if (ctx->first_idr && unit_type == 5) {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
123 alloc_and_copy(poutbuf, poutbuf_size,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
124 ctx->sps_pps_data, ctx->size,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
125 buf, nal_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
126 ctx->first_idr = 0;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
127 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
128 else {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
129 alloc_and_copy(poutbuf, poutbuf_size,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
130 NULL, 0,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
131 buf, nal_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
132 if (!ctx->first_idr && unit_type == 1)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
133 ctx->first_idr = 1;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
134 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
135
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
136 buf += nal_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
137 cumul_size += nal_size + ctx->length_size;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
138 } while (cumul_size < buf_size);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
139
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
140 return 1;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
141 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
142
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
143 static void h264_mp4toannexb_close(AVBitStreamFilterContext *bsfc)
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
144 {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
145 H264BSFContext *ctx = bsfc->priv_data;
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
146 av_freep(&ctx->sps_pps_data);
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
147 }
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
148
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
149 AVBitStreamFilter h264_mp4toannexb_bsf = {
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
150 "h264_mp4toannexb",
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
151 sizeof(H264BSFContext),
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
152 h264_mp4toannexb_filter,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
153 h264_mp4toannexb_close,
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
154 };
679d6ccfffb0 Add a bitstream filter for H.264.
benoit
parents:
diff changeset
155