00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/intreadwrite.h"
00023 #include "avcodec.h"
00024
00025 typedef struct H264BSFContext {
00026 uint8_t length_size;
00027 uint8_t first_idr;
00028 uint8_t *sps_pps_data;
00029 uint32_t size;
00030 } H264BSFContext;
00031
00032 static void alloc_and_copy(uint8_t **poutbuf, int *poutbuf_size,
00033 const uint8_t *sps_pps, uint32_t sps_pps_size,
00034 const uint8_t *in, uint32_t in_size) {
00035 uint32_t offset = *poutbuf_size;
00036 uint8_t nal_header_size = offset ? 3 : 4;
00037
00038 *poutbuf_size += sps_pps_size+in_size+nal_header_size;
00039 *poutbuf = av_realloc(*poutbuf, *poutbuf_size);
00040 if (sps_pps)
00041 memcpy(*poutbuf+offset, sps_pps, sps_pps_size);
00042 memcpy(*poutbuf+sps_pps_size+nal_header_size+offset, in, in_size);
00043 if (!offset)
00044 AV_WB32(*poutbuf+sps_pps_size, 1);
00045 else {
00046 (*poutbuf+offset+sps_pps_size)[0] = (*poutbuf+offset+sps_pps_size)[1] = 0;
00047 (*poutbuf+offset+sps_pps_size)[2] = 1;
00048 }
00049 }
00050
00051 static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
00052 AVCodecContext *avctx, const char *args,
00053 uint8_t **poutbuf, int *poutbuf_size,
00054 const uint8_t *buf, int buf_size,
00055 int keyframe) {
00056 H264BSFContext *ctx = bsfc->priv_data;
00057 uint8_t unit_type;
00058 int32_t nal_size;
00059 uint32_t cumul_size = 0;
00060 const uint8_t *buf_end = buf + buf_size;
00061
00062
00063 if (!avctx->extradata || avctx->extradata_size < 6) {
00064 *poutbuf = (uint8_t*) buf;
00065 *poutbuf_size = buf_size;
00066 return 0;
00067 }
00068
00069
00070 if (!ctx->sps_pps_data) {
00071 uint16_t unit_size;
00072 uint32_t total_size = 0;
00073 uint8_t *out = NULL, unit_nb, sps_done = 0;
00074 const uint8_t *extradata = avctx->extradata+4;
00075 static const uint8_t nalu_header[4] = {0, 0, 0, 1};
00076
00077
00078 ctx->length_size = (*extradata++ & 0x3) + 1;
00079 if (ctx->length_size == 3)
00080 return AVERROR(EINVAL);
00081
00082
00083 unit_nb = *extradata++ & 0x1f;
00084 if (!unit_nb) {
00085 unit_nb = *extradata++;
00086 sps_done++;
00087 }
00088 while (unit_nb--) {
00089 unit_size = AV_RB16(extradata);
00090 total_size += unit_size+4;
00091 if (extradata+2+unit_size > avctx->extradata+avctx->extradata_size) {
00092 av_free(out);
00093 return AVERROR(EINVAL);
00094 }
00095 out = av_realloc(out, total_size);
00096 if (!out)
00097 return AVERROR(ENOMEM);
00098 memcpy(out+total_size-unit_size-4, nalu_header, 4);
00099 memcpy(out+total_size-unit_size, extradata+2, unit_size);
00100 extradata += 2+unit_size;
00101
00102 if (!unit_nb && !sps_done++)
00103 unit_nb = *extradata++;
00104 }
00105
00106 ctx->sps_pps_data = out;
00107 ctx->size = total_size;
00108 ctx->first_idr = 1;
00109 }
00110
00111 *poutbuf_size = 0;
00112 *poutbuf = NULL;
00113 do {
00114 if (buf + ctx->length_size > buf_end)
00115 goto fail;
00116
00117 if (ctx->length_size == 1)
00118 nal_size = buf[0];
00119 else if (ctx->length_size == 2)
00120 nal_size = AV_RB16(buf);
00121 else
00122 nal_size = AV_RB32(buf);
00123
00124 buf += ctx->length_size;
00125 unit_type = *buf & 0x1f;
00126
00127 if (buf + nal_size > buf_end || nal_size < 0)
00128 goto fail;
00129
00130
00131 if (ctx->first_idr && unit_type == 5) {
00132 alloc_and_copy(poutbuf, poutbuf_size,
00133 ctx->sps_pps_data, ctx->size,
00134 buf, nal_size);
00135 ctx->first_idr = 0;
00136 }
00137 else {
00138 alloc_and_copy(poutbuf, poutbuf_size,
00139 NULL, 0,
00140 buf, nal_size);
00141 if (!ctx->first_idr && unit_type == 1)
00142 ctx->first_idr = 1;
00143 }
00144
00145 buf += nal_size;
00146 cumul_size += nal_size + ctx->length_size;
00147 } while (cumul_size < buf_size);
00148
00149 return 1;
00150
00151 fail:
00152 av_freep(poutbuf);
00153 *poutbuf_size = 0;
00154 return AVERROR(EINVAL);
00155 }
00156
00157 static void h264_mp4toannexb_close(AVBitStreamFilterContext *bsfc)
00158 {
00159 H264BSFContext *ctx = bsfc->priv_data;
00160 av_freep(&ctx->sps_pps_data);
00161 }
00162
00163 AVBitStreamFilter h264_mp4toannexb_bsf = {
00164 "h264_mp4toannexb",
00165 sizeof(H264BSFContext),
00166 h264_mp4toannexb_filter,
00167 h264_mp4toannexb_close,
00168 };
00169