X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Favc.c;h=ec50033a0420ea7402c3eb9b0dbbd26c740ee568;hb=a8a751ce9aaad4f466ccd9b0852709e063c2ba74;hp=094a95821f396327ff0a3398aef53ca4f10a7bcd;hpb=6727cfea5e416c32591563a6e91936629ae16185;p=ffmpeg diff --git a/libavformat/avc.c b/libavformat/avc.c index 094a95821f3..ec50033a042 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavcodec/h264.h" #include "avformat.h" #include "avio.h" #include "avc.h" @@ -105,60 +106,92 @@ int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) { - if (len > 6) { - /* check for H.264 start code */ - if (AV_RB32(data) == 0x00000001 || - AV_RB24(data) == 0x000001) { - uint8_t *buf=NULL, *end, *start; - uint32_t sps_size=0, pps_size=0; - uint8_t *sps=0, *pps=0; - - int ret = ff_avc_parse_nal_units_buf(data, &buf, &len); - if (ret < 0) - return ret; - start = buf; - end = buf + len; - - /* look for sps and pps */ - while (end - buf > 4) { - uint32_t size; - uint8_t nal_type; - size = FFMIN(AV_RB32(buf), end - buf - 4); - buf += 4; - nal_type = buf[0] & 0x1f; - - if (nal_type == 7) { /* SPS */ - sps = buf; - sps_size = size; - } else if (nal_type == 8) { /* PPS */ - pps = buf; - pps_size = size; - } - - buf += size; - } + AVIOContext *sps_pb = NULL, *pps_pb = NULL; + uint8_t *buf = NULL, *end, *start = NULL; + uint8_t *sps = NULL, *pps = NULL; + uint32_t sps_size = 0, pps_size = 0; + int ret, nb_sps = 0, nb_pps = 0; + + if (len <= 6) + return AVERROR_INVALIDDATA; - if (!sps || !pps || sps_size < 4 || sps_size > UINT16_MAX || pps_size > UINT16_MAX) - return AVERROR_INVALIDDATA; - - avio_w8(pb, 1); /* version */ - avio_w8(pb, sps[1]); /* profile */ - avio_w8(pb, sps[2]); /* profile compat */ - avio_w8(pb, sps[3]); /* level */ - avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ - avio_w8(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ - - avio_wb16(pb, sps_size); - avio_write(pb, sps, sps_size); - avio_w8(pb, 1); /* number of pps */ - avio_wb16(pb, pps_size); - avio_write(pb, pps, pps_size); - av_free(start); - } else { - avio_write(pb, data, len); + /* check for H.264 start code */ + if (AV_RB32(data) != 0x00000001 && + AV_RB24(data) != 0x000001) { + avio_write(pb, data, len); + return 0; + } + + ret = ff_avc_parse_nal_units_buf(data, &buf, &len); + if (ret < 0) + return ret; + start = buf; + end = buf + len; + + ret = avio_open_dyn_buf(&sps_pb); + if (ret < 0) + goto fail; + ret = avio_open_dyn_buf(&pps_pb); + if (ret < 0) + goto fail; + + /* look for sps and pps */ + while (end - buf > 4) { + uint32_t size; + uint8_t nal_type; + size = FFMIN(AV_RB32(buf), end - buf - 4); + buf += 4; + nal_type = buf[0] & 0x1f; + + if (nal_type == 7) { /* SPS */ + nb_sps++; + if (size > UINT16_MAX || nb_sps >= H264_MAX_SPS_COUNT) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + avio_wb16(sps_pb, size); + avio_write(sps_pb, buf, size); + } else if (nal_type == 8) { /* PPS */ + nb_pps++; + if (size > UINT16_MAX || nb_pps >= H264_MAX_PPS_COUNT) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + avio_wb16(pps_pb, size); + avio_write(pps_pb, buf, size); } + + buf += size; } - return 0; + sps_size = avio_close_dyn_buf(sps_pb, &sps); + pps_size = avio_close_dyn_buf(pps_pb, &pps); + + if (sps_size < 6 || !pps_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + avio_w8(pb, 1); /* version */ + avio_w8(pb, sps[3]); /* profile */ + avio_w8(pb, sps[4]); /* profile compat */ + avio_w8(pb, sps[5]); /* level */ + avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ + avio_w8(pb, 0xe0 | nb_sps); /* 3 bits reserved (111) + 5 bits number of sps */ + + avio_write(pb, sps, sps_size); + avio_w8(pb, nb_pps); /* number of pps */ + avio_write(pb, pps, pps_size); + +fail: + if (!sps) + avio_close_dyn_buf(sps_pb, &sps); + if (!pps) + avio_close_dyn_buf(pps_pb, &pps); + av_free(sps); + av_free(pps); + av_free(start); + + return ret; } int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)