static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *out) { ExtractExtradataContext *s = ctx->priv_data; AVPacket *in; uint8_t *extradata = NULL; int extradata_size; int ret = 0; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; ret = s->extract(ctx, in, &extradata, &extradata_size); if (ret < 0) goto fail; if (extradata) { ret = av_packet_add_side_data(in, AV_PKT_DATA_NEW_EXTRADATA, extradata, extradata_size); if (ret < 0) { av_freep(&extradata); goto fail; } } av_packet_move_ref(out, in); fail: av_packet_free(&in); return ret; }
static int filter_units_filter(AVBSFContext *bsf, AVPacket *out) { FilterUnitsContext *ctx = bsf->priv_data; CodedBitstreamFragment *frag = &ctx->fragment; AVPacket *in = NULL; int err, i, j; while (1) { err = ff_bsf_get_packet(bsf, &in); if (err < 0) return err; if (ctx->mode == NOOP) { av_packet_move_ref(out, in); av_packet_free(&in); return 0; } err = ff_cbs_read_packet(ctx->cbc, frag, in); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); goto fail; } for (i = 0; i < frag->nb_units; i++) { for (j = 0; j < ctx->nb_types; j++) { if (frag->units[i].type == ctx->type_list[j]) break; } if (ctx->mode == REMOVE ? j < ctx->nb_types : j >= ctx->nb_types) { ff_cbs_delete_unit(ctx->cbc, frag, i); --i; } } if (frag->nb_units > 0) break; // Don't return packets with nothing in them. av_packet_free(&in); ff_cbs_fragment_uninit(ctx->cbc, frag); } err = ff_cbs_write_packet(ctx->cbc, out, frag); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); goto fail; } err = av_packet_copy_props(out, in); if (err < 0) goto fail; fail: ff_cbs_fragment_uninit(ctx->cbc, frag); av_packet_free(&in); return err; }
static int remove_extradata(AVBSFContext *ctx, AVPacket *out) { RemoveExtradataContext *s = ctx->priv_data; AVPacket *in; int ret; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; if (s->parser && s->parser->parser->split) { if (s->freq == REMOVE_FREQ_ALL || (s->freq == REMOVE_FREQ_NONKEYFRAME && !(in->flags & AV_PKT_FLAG_KEY)) || (s->freq == REMOVE_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY)) { int i = s->parser->parser->split(s->avctx, in->data, in->size); in->data += i; in->size -= i; } } av_packet_move_ref(out, in); av_packet_free(&in); return 0; }
static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *out) { H264RedundantPPSContext *ctx = bsf->priv_data; AVPacket *in; CodedBitstreamFragment *au = &ctx->access_unit; int au_has_sps; int err, i; err = ff_bsf_get_packet(bsf, &in); if (err < 0) return err; err = ff_cbs_read_packet(ctx->input, au, in); if (err < 0) goto fail; au_has_sps = 0; for (i = 0; i < au->nb_units; i++) { CodedBitstreamUnit *nal = &au->units[i]; if (nal->type == H264_NAL_SPS) au_has_sps = 1; if (nal->type == H264_NAL_PPS) { err = h264_redundant_pps_fixup_pps(ctx, nal->content); if (err < 0) goto fail; if (!au_has_sps) { av_log(bsf, AV_LOG_VERBOSE, "Deleting redundant PPS " "at %"PRId64".\n", in->pts); err = ff_cbs_delete_unit(ctx->input, au, i); if (err < 0) goto fail; } } if (nal->type == H264_NAL_SLICE || nal->type == H264_NAL_IDR_SLICE) { H264RawSlice *slice = nal->content; h264_redundant_pps_fixup_slice(ctx, &slice->header); } } err = ff_cbs_write_packet(ctx->output, out, au); if (err < 0) goto fail; err = av_packet_copy_props(out, in); if (err < 0) goto fail; err = 0; fail: ff_cbs_fragment_uninit(ctx->output, au); av_packet_free(&in); if (err < 0) av_packet_unref(out); return err; }
static int mjpeg2jpeg_filter(AVBSFContext *ctx, AVPacket *out) { AVPacket *in; int ret = 0; int input_skip, output_size; uint8_t *output; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; if (in->size < 12) { av_log(ctx, AV_LOG_ERROR, "input is truncated\n"); ret = AVERROR_INVALIDDATA; goto fail; } if (AV_RB16(in->data) != 0xffd8) { av_log(ctx, AV_LOG_ERROR, "input is not MJPEG\n"); ret = AVERROR_INVALIDDATA; goto fail; } if (in->data[2] == 0xff && in->data[3] == APP0) { input_skip = (in->data[4] << 8) + in->data[5] + 4; } else { input_skip = 2; } if (in->size < input_skip) { av_log(ctx, AV_LOG_ERROR, "input is truncated\n"); ret = AVERROR_INVALIDDATA; goto fail; } output_size = in->size - input_skip + sizeof(jpeg_header) + dht_segment_size; ret = av_new_packet(out, output_size); if (ret < 0) goto fail; output = out->data; output = append(output, jpeg_header, sizeof(jpeg_header)); output = append_dht_segment(output); output = append(output, in->data + input_skip, in->size - input_skip); ret = av_packet_copy_props(out, in); if (ret < 0) goto fail; fail: if (ret < 0) av_packet_unref(out); av_packet_free(&in); return ret; }
static int chomp_filter(AVBSFContext *ctx, AVPacket *out) { AVPacket *in; int ret; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; while (in->size > 0 && !in->data[in->size - 1]) in->size--; av_packet_move_ref(out, in); av_packet_free(&in); return 0; }
static int trace_headers(AVBSFContext *bsf, AVPacket *out) { TraceHeadersContext *ctx = bsf->priv_data; CodedBitstreamFragment au; AVPacket *in; char tmp[256] = { 0 }; int err; err = ff_bsf_get_packet(bsf, &in); if (err < 0) return err; if (in->flags & AV_PKT_FLAG_KEY) av_strlcat(tmp, ", key frame", sizeof(tmp)); if (in->flags & AV_PKT_FLAG_CORRUPT) av_strlcat(tmp, ", corrupt", sizeof(tmp)); if (in->pts != AV_NOPTS_VALUE) av_strlcatf(tmp, sizeof(tmp), ", pts %"PRId64, in->pts); else av_strlcat(tmp, ", no pts", sizeof(tmp)); if (in->dts != AV_NOPTS_VALUE) av_strlcatf(tmp, sizeof(tmp), ", dts %"PRId64, in->dts); else av_strlcat(tmp, ", no dts", sizeof(tmp)); if (in->duration > 0) av_strlcatf(tmp, sizeof(tmp), ", duration %"PRId64, in->duration); av_log(bsf, AV_LOG_INFO, "Packet: %d bytes%s.\n", in->size, tmp); err = ff_cbs_read_packet(&ctx->cbc, &au, in); if (err < 0) return err; ff_cbs_fragment_uninit(&ctx->cbc, &au); av_packet_move_ref(out, in); av_packet_free(&in); return 0; }
static int dump_extradata(AVBSFContext *ctx, AVPacket *out) { DumpExtradataContext *s = ctx->priv_data; AVPacket *in; int ret = 0; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; if (ctx->par_in->extradata && (s->freq == DUMP_FREQ_ALL || (s->freq == DUMP_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY))) { if (in->size >= INT_MAX - ctx->par_in->extradata_size) { ret = AVERROR(ERANGE); goto fail; } ret = av_new_packet(out, in->size + ctx->par_in->extradata_size); if (ret < 0) goto fail; ret = av_packet_copy_props(out, in); if (ret < 0) { av_packet_unref(out); goto fail; } memcpy(out->data, ctx->par_in->extradata, ctx->par_in->extradata_size); memcpy(out->data + ctx->par_in->extradata_size, in->data, in->size); } else { av_packet_move_ref(out, in); } fail: av_packet_free(&in); return ret; }
static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out) { H265MetadataContext *ctx = bsf->priv_data; AVPacket *in = NULL; CodedBitstreamFragment *au = &ctx->access_unit; int err, i; err = ff_bsf_get_packet(bsf, &in); if (err < 0) goto fail; err = ff_cbs_read_packet(ctx->cbc, au, in); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); goto fail; } if (au->nb_units == 0) { av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n"); err = AVERROR_INVALIDDATA; goto fail; } // If an AUD is present, it must be the first NAL unit. if (au->units[0].type == HEVC_NAL_AUD) { if (ctx->aud == REMOVE) ff_cbs_delete_unit(ctx->cbc, au, 0); } else { if (ctx->aud == INSERT) { H265RawAUD *aud = &ctx->aud_nal; int pic_type = 0, temporal_id = 8, layer_id = 0; for (i = 0; i < au->nb_units; i++) { const H265RawNALUnitHeader *nal = au->units[i].content; if (!nal) continue; if (nal->nuh_temporal_id_plus1 < temporal_id + 1) temporal_id = nal->nuh_temporal_id_plus1 - 1; if (au->units[i].type <= HEVC_NAL_RSV_VCL31) { const H265RawSlice *slice = au->units[i].content; layer_id = nal->nuh_layer_id; if (slice->header.slice_type == HEVC_SLICE_B && pic_type < 2) pic_type = 2; if (slice->header.slice_type == HEVC_SLICE_P && pic_type < 1) pic_type = 1; } } aud->nal_unit_header = (H265RawNALUnitHeader) { .nal_unit_type = HEVC_NAL_AUD, .nuh_layer_id = layer_id, .nuh_temporal_id_plus1 = temporal_id + 1, }; aud->pic_type = pic_type; err = ff_cbs_insert_unit_content(ctx->cbc, au, 0, HEVC_NAL_AUD, aud, NULL); if (err) { av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); goto fail; } } } for (i = 0; i < au->nb_units; i++) { if (au->units[i].type == HEVC_NAL_VPS) { err = h265_metadata_update_vps(bsf, au->units[i].content); if (err < 0) goto fail; } if (au->units[i].type == HEVC_NAL_SPS) { err = h265_metadata_update_sps(bsf, au->units[i].content); if (err < 0) goto fail; } } err = ff_cbs_write_packet(ctx->cbc, out, au); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); goto fail; } err = av_packet_copy_props(out, in); if (err < 0) goto fail; err = 0; fail: ff_cbs_fragment_uninit(ctx->cbc, au); av_packet_free(&in); return err; }
static int vp9_raw_reorder_filter(AVBSFContext *bsf, AVPacket *out) { VP9RawReorderContext *ctx = bsf->priv_data; VP9RawReorderFrame *frame; AVPacket *in; int err, s; if (ctx->next_frame) { frame = ctx->next_frame; } else { err = ff_bsf_get_packet(bsf, &in); if (err < 0) { if (err == AVERROR_EOF) return vp9_raw_reorder_make_output(bsf, out, NULL); return err; } if (in->data[in->size - 1] & 0xe0 == 0xc0) { av_log(bsf, AV_LOG_ERROR, "Input in superframes is not " "supported.\n"); av_packet_free(&in); return AVERROR(ENOSYS); } frame = av_mallocz(sizeof(*frame)); if (!frame) { av_packet_free(&in); return AVERROR(ENOMEM); } frame->packet = in; frame->pts = in->pts; frame->sequence = ++ctx->sequence; err = vp9_raw_reorder_frame_parse(bsf, frame); if (err) { av_log(bsf, AV_LOG_ERROR, "Failed to parse input " "frame: %d.\n", err); goto fail; } frame->needs_output = 1; frame->needs_display = frame->pts != AV_NOPTS_VALUE; if (frame->show_existing_frame) av_log(bsf, AV_LOG_DEBUG, "Show frame %"PRId64" " "(%"PRId64"): show %u.\n", frame->sequence, frame->pts, frame->frame_to_show); else av_log(bsf, AV_LOG_DEBUG, "New frame %"PRId64" " "(%"PRId64"): type %u show %u refresh %02x.\n", frame->sequence, frame->pts, frame->frame_type, frame->show_frame, frame->refresh_frame_flags); ctx->next_frame = frame; } for (s = 0; s < FRAME_SLOTS; s++) { if (!(frame->refresh_frame_flags & (1 << s))) continue; if (ctx->slot[s] && ctx->slot[s]->needs_display && ctx->slot[s]->slots == (1 << s)) { // We are overwriting this slot, which is last reference // to the frame previously present in it. In order to be // a valid stream, that frame must already have been // displayed before the pts of the current frame. err = vp9_raw_reorder_make_output(bsf, out, ctx->slot[s]); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to create " "output overwriting slot %d: %d.\n", s, err); // Clear the slot anyway, so we don't end up // in an infinite loop. vp9_raw_reorder_clear_slot(ctx, s); return AVERROR_INVALIDDATA; } return 0; } vp9_raw_reorder_clear_slot(ctx, s); } for (s = 0; s < FRAME_SLOTS; s++) { if (!(frame->refresh_frame_flags & (1 << s))) continue; ctx->slot[s] = frame; } frame->slots = frame->refresh_frame_flags; if (!frame->refresh_frame_flags) { err = vp9_raw_reorder_make_output(bsf, out, frame); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to create output " "for transient frame.\n"); ctx->next_frame = NULL; return AVERROR_INVALIDDATA; } if (!frame->needs_display) { vp9_raw_reorder_frame_free(&frame); ctx->next_frame = NULL; } return 0; } ctx->next_frame = NULL; return AVERROR(EAGAIN); fail: vp9_raw_reorder_frame_free(&frame); return err; }
static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) { UnpackBFramesBSFContext *s = ctx->priv_data; int pos_p = -1, nb_vop = 0, pos_vop2 = -1, ret = 0; AVPacket *in; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; scan_buffer(in->data, in->size, &pos_p, &nb_vop, &pos_vop2); av_log(ctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop); if (pos_vop2 >= 0) { if (s->b_frame_buf) { av_log(ctx, AV_LOG_WARNING, "Missing one N-VOP packet, discarding one B-frame.\n"); av_freep(&s->b_frame_buf); s->b_frame_buf_size = 0; } /* store the packed B-frame in the BSFContext */ s->b_frame_buf_size = in->size - pos_vop2; s->b_frame_buf = create_new_buffer(in->data + pos_vop2, s->b_frame_buf_size); if (!s->b_frame_buf) { s->b_frame_buf_size = 0; av_packet_free(&in); return AVERROR(ENOMEM); } } if (nb_vop > 2) { av_log(ctx, AV_LOG_WARNING, "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop); } if (nb_vop == 1 && s->b_frame_buf) { /* use frame from BSFContext */ ret = av_packet_copy_props(out, in); if (ret < 0) { av_packet_free(&in); return ret; } ret = av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size); if (ret < 0) { av_packet_free(&in); return ret; } if (in->size <= MAX_NVOP_SIZE) { /* N-VOP */ av_log(ctx, AV_LOG_DEBUG, "Skipping N-VOP.\n"); s->b_frame_buf = NULL; s->b_frame_buf_size = 0; } else { /* copy packet into BSFContext */ s->b_frame_buf_size = in->size; s->b_frame_buf = create_new_buffer(in->data, in->size); if (!s->b_frame_buf) { s->b_frame_buf_size = 0; av_packet_unref(out); av_packet_free(&in); return AVERROR(ENOMEM); } } } else if (nb_vop >= 2) { /* use first frame of the packet */ av_packet_move_ref(out, in); out->size = pos_vop2; } else if (pos_p >= 0) { av_log(ctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n"); av_packet_move_ref(out, in); /* remove 'p' (packed) from the end of the (DivX) userdata string */ out->data[pos_p] = '\0'; } else { /* copy packet */ av_packet_move_ref(out, in); } av_packet_free(&in); return 0; }
static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) { H264BSFContext *s = ctx->priv_data; AVPacket *in; uint8_t unit_type; int32_t nal_size; uint32_t cumul_size = 0; const uint8_t *buf; const uint8_t *buf_end; int buf_size; int ret = 0, i; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; /* nothing to filter */ if (!s->extradata_parsed) { av_packet_move_ref(out, in); av_packet_free(&in); return 0; } buf = in->data; buf_size = in->size; buf_end = in->data + in->size; do { ret= AVERROR(EINVAL); if (buf + s->length_size > buf_end) goto fail; for (nal_size = 0, i = 0; i<s->length_size; i++) nal_size = (nal_size << 8) | buf[i]; buf += s->length_size; unit_type = *buf & 0x1f; if (nal_size > buf_end - buf || nal_size < 0) goto fail; if (unit_type == 7) s->idr_sps_seen = s->new_idr = 1; else if (unit_type == 8) { s->idr_pps_seen = s->new_idr = 1; /* if SPS has not been seen yet, prepend the AVCC one to PPS */ if (!s->idr_sps_seen) { if (s->sps_offset == -1) av_log(ctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n"); else { if ((ret = alloc_and_copy(out, ctx->par_out->extradata + s->sps_offset, s->pps_offset != -1 ? s->pps_offset : ctx->par_out->extradata_size - s->sps_offset, buf, nal_size)) < 0) goto fail; s->idr_sps_seen = 1; goto next_nal; } } } /* if this is a new IDR picture following an IDR picture, reset the idr flag. * Just check first_mb_in_slice to be 0 as this is the simplest solution. * This could be checking idr_pic_id instead, but would complexify the parsing. */ if (!s->new_idr && unit_type == 5 && (buf[1] & 0x80)) s->new_idr = 1; /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ if (s->new_idr && unit_type == 5 && !s->idr_sps_seen && !s->idr_pps_seen) { if ((ret=alloc_and_copy(out, ctx->par_out->extradata, ctx->par_out->extradata_size, buf, nal_size)) < 0) goto fail; s->new_idr = 0; /* if only SPS has been seen, also insert PPS */ } else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) { if (s->pps_offset == -1) { av_log(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) goto fail; } else if ((ret = alloc_and_copy(out, ctx->par_out->extradata + s->pps_offset, ctx->par_out->extradata_size - s->pps_offset, buf, nal_size)) < 0) goto fail; } else { if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) goto fail; if (!s->new_idr && unit_type == 1) { s->new_idr = 1; s->idr_sps_seen = 0; s->idr_pps_seen = 0; } } next_nal: buf += nal_size; cumul_size += nal_size + s->length_size; } while (cumul_size < buf_size); ret = av_packet_copy_props(out, in); if (ret < 0) goto fail; fail: if (ret < 0) av_packet_unref(out); av_packet_free(&in); return ret; }
static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) { H264MetadataContext *ctx = bsf->priv_data; AVPacket *in = NULL; CodedBitstreamFragment *au = &ctx->access_unit; int err, i, j, has_sps; H264RawAUD aud; uint8_t *displaymatrix_side_data = NULL; size_t displaymatrix_side_data_size = 0; err = ff_bsf_get_packet(bsf, &in); if (err < 0) return err; err = ff_cbs_read_packet(ctx->cbc, au, in); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); goto fail; } if (au->nb_units == 0) { av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n"); err = AVERROR_INVALIDDATA; goto fail; } // If an AUD is present, it must be the first NAL unit. if (au->units[0].type == H264_NAL_AUD) { if (ctx->aud == REMOVE) ff_cbs_delete_unit(ctx->cbc, au, 0); } else { if (ctx->aud == INSERT) { static const int primary_pic_type_table[] = { 0x084, // 2, 7 0x0a5, // 0, 2, 5, 7 0x0e7, // 0, 1, 2, 5, 6, 7 0x210, // 4, 9 0x318, // 3, 4, 8, 9 0x294, // 2, 4, 7, 9 0x3bd, // 0, 2, 3, 4, 5, 7, 8, 9 0x3ff, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int primary_pic_type_mask = 0xff; for (i = 0; i < au->nb_units; i++) { if (au->units[i].type == H264_NAL_SLICE || au->units[i].type == H264_NAL_IDR_SLICE) { H264RawSlice *slice = au->units[i].content; for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++) { if (!(primary_pic_type_table[j] & (1 << slice->header.slice_type))) primary_pic_type_mask &= ~(1 << j); } } } for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++) if (primary_pic_type_mask & (1 << j)) break; if (j >= FF_ARRAY_ELEMS(primary_pic_type_table)) { av_log(bsf, AV_LOG_ERROR, "No usable primary_pic_type: " "invalid slice types?\n"); err = AVERROR_INVALIDDATA; goto fail; } aud = (H264RawAUD) { .nal_unit_header.nal_unit_type = H264_NAL_AUD, .primary_pic_type = j, }; err = ff_cbs_insert_unit_content(ctx->cbc, au, 0, H264_NAL_AUD, &aud, NULL); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); goto fail; } } } has_sps = 0; for (i = 0; i < au->nb_units; i++) { if (au->units[i].type == H264_NAL_SPS) { err = h264_metadata_update_sps(bsf, au->units[i].content); if (err < 0) goto fail; has_sps = 1; } } // Only insert the SEI in access units containing SPSs, and also // unconditionally in the first access unit we ever see. if (ctx->sei_user_data && (has_sps || !ctx->done_first_au)) { H264RawSEIPayload payload = { .payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED, }; H264RawSEIUserDataUnregistered *udu = &payload.payload.user_data_unregistered; for (i = j = 0; j < 32 && ctx->sei_user_data[i]; i++) { int c, v; c = ctx->sei_user_data[i]; if (c == '-') { continue; } else if (av_isxdigit(c)) { c = av_tolower(c); v = (c <= '9' ? c - '0' : c - 'a' + 10); } else { goto invalid_user_data; } if (i & 1) udu->uuid_iso_iec_11578[j / 2] |= v; else udu->uuid_iso_iec_11578[j / 2] = v << 4; ++j; } if (j == 32 && ctx->sei_user_data[i] == '+') { size_t len = strlen(ctx->sei_user_data + i + 1); udu->data_ref = av_buffer_alloc(len + 1); if (!udu->data_ref) { err = AVERROR(ENOMEM); goto fail; } udu->data = udu->data_ref->data; udu->data_length = len + 1; memcpy(udu->data, ctx->sei_user_data + i + 1, len + 1); err = ff_cbs_h264_add_sei_message(ctx->cbc, au, &payload); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to add user data SEI " "message to access unit.\n"); goto fail; } } else { invalid_user_data: av_log(bsf, AV_LOG_ERROR, "Invalid user data: " "must be \"UUID+string\".\n"); err = AVERROR(EINVAL); goto fail; } } if (ctx->delete_filler) { for (i = 0; i < au->nb_units; i++) { if (au->units[i].type == H264_NAL_FILLER_DATA) { // Filler NAL units. err = ff_cbs_delete_unit(ctx->cbc, au, i); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to delete " "filler NAL.\n"); goto fail; } --i; continue; } if (au->units[i].type == H264_NAL_SEI) { // Filler SEI messages. H264RawSEI *sei = au->units[i].content; for (j = 0; j < sei->payload_count; j++) { if (sei->payload[j].payload_type == H264_SEI_TYPE_FILLER_PAYLOAD) { err = ff_cbs_h264_delete_sei_message(ctx->cbc, au, &au->units[i], j); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to delete " "filler SEI message.\n"); goto fail; } // Renumbering might have happened, start again at // the same NAL unit position. --i; break; } } } } } if (ctx->display_orientation != PASS) { for (i = 0; i < au->nb_units; i++) { H264RawSEI *sei; if (au->units[i].type != H264_NAL_SEI) continue; sei = au->units[i].content; for (j = 0; j < sei->payload_count; j++) { H264RawSEIDisplayOrientation *disp; int32_t *matrix; if (sei->payload[j].payload_type != H264_SEI_TYPE_DISPLAY_ORIENTATION) continue; disp = &sei->payload[j].payload.display_orientation; if (ctx->display_orientation == REMOVE || ctx->display_orientation == INSERT) { err = ff_cbs_h264_delete_sei_message(ctx->cbc, au, &au->units[i], j); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to delete " "display orientation SEI message.\n"); goto fail; } --i; break; } matrix = av_mallocz(9 * sizeof(int32_t)); if (!matrix) { err = AVERROR(ENOMEM); goto fail; } av_display_rotation_set(matrix, disp->anticlockwise_rotation * 180.0 / 65536.0); av_display_matrix_flip(matrix, disp->hor_flip, disp->ver_flip); // If there are multiple display orientation messages in an // access unit then ignore all but the last one. av_freep(&displaymatrix_side_data); displaymatrix_side_data = (uint8_t*)matrix; displaymatrix_side_data_size = 9 * sizeof(int32_t); } } } if (ctx->display_orientation == INSERT) { H264RawSEIPayload payload = { .payload_type = H264_SEI_TYPE_DISPLAY_ORIENTATION, }; H264RawSEIDisplayOrientation *disp = &payload.payload.display_orientation; uint8_t *data; int size; int write = 0; data = av_packet_get_side_data(in, AV_PKT_DATA_DISPLAYMATRIX, &size); if (data && size >= 9 * sizeof(int32_t)) { int32_t matrix[9]; int hflip, vflip; double angle; memcpy(matrix, data, sizeof(matrix)); hflip = vflip = 0; if (matrix[0] < 0 && matrix[4] > 0) hflip = 1; else if (matrix[0] > 0 && matrix[4] < 0) vflip = 1; av_display_matrix_flip(matrix, hflip, vflip); angle = av_display_rotation_get(matrix); if (!(angle >= -180.0 && angle <= 180.0 /* also excludes NaN */) || matrix[2] != 0 || matrix[5] != 0 || matrix[6] != 0 || matrix[7] != 0) { av_log(bsf, AV_LOG_WARNING, "Input display matrix is not " "representable in H.264 parameters.\n"); } else { disp->hor_flip = hflip; disp->ver_flip = vflip; disp->anticlockwise_rotation = (uint16_t)rint((angle >= 0.0 ? angle : angle + 360.0) * 65536.0 / 360.0); write = 1; } } if (has_sps || !ctx->done_first_au) { if (!isnan(ctx->rotate)) { disp->anticlockwise_rotation = (uint16_t)rint((ctx->rotate >= 0.0 ? ctx->rotate : ctx->rotate + 360.0) * 65536.0 / 360.0); write = 1; } if (ctx->flip) { disp->hor_flip = !!(ctx->flip & FLIP_HORIZONTAL); disp->ver_flip = !!(ctx->flip & FLIP_VERTICAL); write = 1; } } if (write) { disp->display_orientation_repetition_period = 1; err = ff_cbs_h264_add_sei_message(ctx->cbc, au, &payload); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to add display orientation " "SEI message to access unit.\n"); goto fail; } } }
static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) { H264BSFContext *s = ctx->priv_data; AVPacket *in; uint8_t unit_type; int32_t nal_size; uint32_t cumul_size = 0; const uint8_t *buf; const uint8_t *buf_end; int buf_size; int ret = 0; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) return ret; /* nothing to filter */ if (!s->extradata_parsed) { av_packet_move_ref(out, in); av_packet_free(&in); return 0; } buf = in->data; buf_size = in->size; buf_end = in->data + in->size; do { if (buf + s->length_size > buf_end) goto fail; if (s->length_size == 1) { nal_size = buf[0]; } else if (s->length_size == 2) { nal_size = AV_RB16(buf); } else nal_size = AV_RB32(buf); buf += s->length_size; unit_type = *buf & 0x1f; if (buf + nal_size > buf_end || nal_size < 0) goto fail; /* prepend only to the first type 5 NAL unit of an IDR picture */ if (s->first_idr && unit_type == 5) { if (alloc_and_copy(out, ctx->par_out->extradata, ctx->par_out->extradata_size, buf, nal_size) < 0) goto fail; s->first_idr = 0; } else { if (alloc_and_copy(out, NULL, 0, buf, nal_size) < 0) goto fail; if (!s->first_idr && unit_type == 1) s->first_idr = 1; } buf += nal_size; cumul_size += nal_size + s->length_size; } while (cumul_size < buf_size); ret = av_packet_copy_props(out, in); if (ret < 0) goto fail; fail: if (ret < 0) av_packet_unref(out); av_packet_free(&in); return ret; }