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 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 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 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 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; } } }