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