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/avassert.h" 25#include "libavutil/intreadwrite.h" 26#include "libavutil/mem.h" 27#ifdef OHOS_DRM 28#include "libavutil/encryption_info.h" 29#endif 30 31#include "bsf.h" 32#include "bsf_internal.h" 33#include "bytestream.h" 34#include "defs.h" 35#include "h264.h" 36 37typedef struct H264BSFContext { 38 uint8_t *sps; 39 uint8_t *pps; 40 int sps_size; 41 int pps_size; 42 uint8_t length_size; 43 uint8_t new_idr; 44 uint8_t idr_sps_seen; 45 uint8_t idr_pps_seen; 46 int extradata_parsed; 47} H264BSFContext; 48 49static void count_or_copy(uint8_t **out, uint64_t *out_size, 50 const uint8_t *in, int in_size, int ps, int copy) 51{ 52#ifdef OHOS_OPT_COMPAT 53 uint8_t start_code_size = ps < 0 ? 0 : 4; 54#else 55 uint8_t start_code_size = ps < 0 ? 0 : *out_size == 0 || ps ? 4 : 3; 56#endif 57 if (copy) { 58 memcpy(*out + start_code_size, in, in_size); 59 if (start_code_size == 4) { 60 AV_WB32(*out, 1); 61 } else if (start_code_size) { 62 (*out)[0] = 63 (*out)[1] = 0; 64 (*out)[2] = 1; 65 } 66 *out += start_code_size + in_size; 67 } 68 *out_size += start_code_size + in_size; 69} 70 71static int h264_extradata_to_annexb(AVBSFContext *ctx, const int padding) 72{ 73 H264BSFContext *s = ctx->priv_data; 74 GetByteContext ogb, *gb = &ogb; 75 uint16_t unit_size; 76 uint32_t total_size = 0; 77 uint8_t *out = NULL, unit_nb, sps_done = 0; 78 static const uint8_t nalu_header[4] = { 0, 0, 0, 1 }; 79 int length_size, pps_offset = 0; 80 81 bytestream2_init(gb, ctx->par_in->extradata, ctx->par_in->extradata_size); 82 83 bytestream2_skipu(gb, 4); 84 85 /* retrieve length coded size */ 86 length_size = (bytestream2_get_byteu(gb) & 0x3) + 1; 87 88 /* retrieve sps and pps unit(s) */ 89 unit_nb = bytestream2_get_byteu(gb) & 0x1f; /* number of sps unit(s) */ 90 if (!unit_nb) { 91 goto pps; 92 } 93 94 while (unit_nb--) { 95 int err; 96 97 /* possible overread ok due to padding */ 98 unit_size = bytestream2_get_be16u(gb); 99 total_size += unit_size + 4; 100 av_assert1(total_size <= INT_MAX - padding); 101 if (bytestream2_get_bytes_left(gb) < unit_size + !sps_done) { 102 av_log(ctx, AV_LOG_ERROR, "Global extradata truncated, " 103 "corrupted stream or invalid MP4/AVCC bitstream\n"); 104 av_free(out); 105 return AVERROR_INVALIDDATA; 106 } 107 if ((err = av_reallocp(&out, total_size + padding)) < 0) 108 return err; 109 memcpy(out + total_size - unit_size - 4, nalu_header, 4); 110 bytestream2_get_bufferu(gb, out + total_size - unit_size, unit_size); 111pps: 112 if (!unit_nb && !sps_done++) { 113 unit_nb = bytestream2_get_byteu(gb); /* number of pps unit(s) */ 114 pps_offset = total_size; 115 } 116 } 117 118 if (out) 119 memset(out + total_size, 0, padding); 120 121 if (pps_offset) { 122 s->sps = out; 123 s->sps_size = pps_offset; 124 } else { 125 av_log(ctx, AV_LOG_WARNING, 126 "Warning: SPS NALU missing or invalid. " 127 "The resulting stream may not play.\n"); 128 } 129 if (pps_offset < total_size) { 130 s->pps = out + pps_offset; 131 s->pps_size = total_size - pps_offset; 132 } else { 133 av_log(ctx, AV_LOG_WARNING, 134 "Warning: PPS NALU missing or invalid. " 135 "The resulting stream may not play.\n"); 136 } 137 138 av_freep(&ctx->par_out->extradata); 139 ctx->par_out->extradata = out; 140 ctx->par_out->extradata_size = total_size; 141 142 return length_size; 143} 144 145static int h264_mp4toannexb_init(AVBSFContext *ctx) 146{ 147 H264BSFContext *s = ctx->priv_data; 148 int extra_size = ctx->par_in->extradata_size; 149 int ret; 150 151 /* retrieve sps and pps NAL units from extradata */ 152 if (!extra_size || 153 (extra_size >= 3 && AV_RB24(ctx->par_in->extradata) == 1) || 154 (extra_size >= 4 && AV_RB32(ctx->par_in->extradata) == 1)) { 155 av_log(ctx, AV_LOG_VERBOSE, 156 "The input looks like it is Annex B already\n"); 157 } else if (extra_size >= 7) { 158 ret = h264_extradata_to_annexb(ctx, AV_INPUT_BUFFER_PADDING_SIZE); 159 if (ret < 0) 160 return ret; 161 162 s->length_size = ret; 163 s->new_idr = 1; 164 s->idr_sps_seen = 0; 165 s->idr_pps_seen = 0; 166 s->extradata_parsed = 1; 167 } else { 168 av_log(ctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", extra_size); 169 return AVERROR_INVALIDDATA; 170 } 171 172 return 0; 173} 174 175#ifdef OHOS_DRM 176static void h264_mp4toannexb_modify_encryption_info(AVPacket *pkt, uint64_t new_data_size, uint64_t old_data_size, 177 int copy) 178{ 179 AV_DrmCencInfo *side_data = NULL; 180 size_t side_data_size = 0; 181 if ((copy == 0) || (new_data_size == old_data_size)) { 182 return; 183 } 184 side_data = (AV_DrmCencInfo *)av_packet_get_side_data(pkt, AV_PKT_DATA_ENCRYPTION_INFO, &side_data_size); 185 if ((side_data != NULL) && (side_data_size != 0)) { 186 uint64_t total_size = 0; 187 for (uint32_t i = 0; i < side_data->sub_sample_num; i++) { 188 total_size += 189 (uint64_t)(side_data->sub_samples[i].clear_header_len + side_data->sub_samples[i].pay_load_len); 190 if (total_size < new_data_size) { 191 continue; 192 } 193 if (new_data_size > old_data_size) { 194 side_data->sub_samples[i].clear_header_len += (uint32_t)(new_data_size - old_data_size); 195 } else { 196 uint32_t diff_size = (uint32_t)(old_data_size - new_data_size); 197 if (side_data->sub_samples[i].clear_header_len < diff_size) { 198 return; 199 } 200 side_data->sub_samples[i].clear_header_len -= diff_size; 201 } 202 break; 203 } 204 } 205 return; 206} 207#endif 208 209static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *opkt) 210{ 211 H264BSFContext *s = ctx->priv_data; 212 AVPacket *in; 213 uint8_t unit_type, new_idr, sps_seen, pps_seen; 214 const uint8_t *buf; 215 const uint8_t *buf_end; 216 uint8_t *out; 217 uint64_t out_size; 218 int ret; 219#ifdef OHOS_DRM 220 uint64_t old_out_size; 221#endif 222 223 ret = ff_bsf_get_packet(ctx, &in); 224 if (ret < 0) 225 return ret; 226 227 /* nothing to filter */ 228 if (!s->extradata_parsed) { 229 av_packet_move_ref(opkt, in); 230 av_packet_free(&in); 231 return 0; 232 } 233 234 buf_end = in->data + in->size; 235 236#define LOG_ONCE(...) \ 237 if (j) \ 238 av_log(__VA_ARGS__) 239 for (int j = 0; j < 2; j++) { 240 buf = in->data; 241 new_idr = s->new_idr; 242 sps_seen = s->idr_sps_seen; 243 pps_seen = s->idr_pps_seen; 244 out_size = 0; 245#ifdef OHOS_DRM 246 old_out_size = out_size; 247#endif 248 249 do { 250 uint32_t nal_size = 0; 251 252 /* possible overread ok due to padding */ 253 for (int i = 0; i < s->length_size; i++) 254 nal_size = (nal_size << 8) | buf[i]; 255 256 buf += s->length_size; 257 258 /* This check requires the cast as the right side might 259 * otherwise be promoted to an unsigned value. */ 260 if ((int64_t)nal_size > buf_end - buf) { 261 ret = AVERROR_INVALIDDATA; 262 goto fail; 263 } 264 265 if (!nal_size) 266 continue; 267 268 unit_type = *buf & 0x1f; 269 270 if (unit_type == H264_NAL_SPS) { 271 sps_seen = new_idr = 1; 272 } else if (unit_type == H264_NAL_PPS) { 273 pps_seen = new_idr = 1; 274 /* if SPS has not been seen yet, prepend the AVCC one to PPS */ 275 if (!sps_seen) { 276 if (!s->sps_size) { 277 LOG_ONCE(ctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n"); 278 } else { 279 count_or_copy(&out, &out_size, s->sps, s->sps_size, -1, j); 280#ifdef OHOS_DRM 281 h264_mp4toannexb_modify_encryption_info(in, out_size, old_out_size, j); 282 old_out_size = out_size; 283#endif 284 sps_seen = 1; 285 } 286 } 287 } 288 289 /* If this is a new IDR picture following an IDR picture, reset the idr flag. 290 * Just check first_mb_in_slice to be 0 as this is the simplest solution. 291 * This could be checking idr_pic_id instead, but would complexify the parsing. */ 292 if (!new_idr && unit_type == H264_NAL_IDR_SLICE && (buf[1] & 0x80)) 293 new_idr = 1; 294 295 /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ 296 if (new_idr && unit_type == H264_NAL_IDR_SLICE && !sps_seen && !pps_seen) { 297 if (ctx->par_out->extradata) 298 count_or_copy(&out, &out_size, ctx->par_out->extradata, 299 ctx->par_out->extradata_size, -1, j); 300#ifdef OHOS_DRM 301 h264_mp4toannexb_modify_encryption_info(in, out_size, old_out_size, j); 302 old_out_size = out_size; 303#endif 304 new_idr = 0; 305 /* if only SPS has been seen, also insert PPS */ 306 } else if (new_idr && unit_type == H264_NAL_IDR_SLICE && sps_seen && !pps_seen) { 307 if (!s->pps_size) { 308 LOG_ONCE(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); 309 } else { 310 count_or_copy(&out, &out_size, s->pps, s->pps_size, -1, j); 311#ifdef OHOS_DRM 312 h264_mp4toannexb_modify_encryption_info(in, out_size, old_out_size, j); 313 old_out_size = out_size; 314#endif 315 } 316 } 317 318 count_or_copy(&out, &out_size, buf, nal_size, 319 unit_type == H264_NAL_SPS || unit_type == H264_NAL_PPS, j); 320#ifdef OHOS_DRM 321 h264_mp4toannexb_modify_encryption_info(in, out_size, 322 (uint64_t)(nal_size + old_out_size + s->length_size), j); 323 old_out_size = out_size; 324#endif 325 if (!new_idr && unit_type == H264_NAL_SLICE) { 326 new_idr = 1; 327 sps_seen = 0; 328 pps_seen = 0; 329 } 330 331 buf += nal_size; 332 } while (buf < buf_end); 333 334 if (!j) { 335 if (out_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { 336 ret = AVERROR_INVALIDDATA; 337 goto fail; 338 } 339 ret = av_new_packet(opkt, out_size); 340 if (ret < 0) 341 goto fail; 342 out = opkt->data; 343 } 344 } 345#undef LOG_ONCE 346 347 av_assert1(out_size == opkt->size); 348 349 s->new_idr = new_idr; 350 s->idr_sps_seen = sps_seen; 351 s->idr_pps_seen = pps_seen; 352 353 ret = av_packet_copy_props(opkt, in); 354 if (ret < 0) 355 goto fail; 356 357fail: 358 if (ret < 0) 359 av_packet_unref(opkt); 360 av_packet_free(&in); 361 362 return ret; 363} 364 365static void h264_mp4toannexb_flush(AVBSFContext *ctx) 366{ 367 H264BSFContext *s = ctx->priv_data; 368 369 s->idr_sps_seen = 0; 370 s->idr_pps_seen = 0; 371 s->new_idr = s->extradata_parsed; 372} 373 374static const enum AVCodecID codec_ids[] = { 375 AV_CODEC_ID_H264, AV_CODEC_ID_NONE, 376}; 377 378const FFBitStreamFilter ff_h264_mp4toannexb_bsf = { 379 .p.name = "h264_mp4toannexb", 380 .p.codec_ids = codec_ids, 381 .priv_data_size = sizeof(H264BSFContext), 382 .init = h264_mp4toannexb_init, 383 .filter = h264_mp4toannexb_filter, 384 .flush = h264_mp4toannexb_flush, 385}; 386