示例#1
0
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;
}
示例#2
0
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;
}
示例#5
0
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;
}
示例#6
0
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;
}
示例#7
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;
}
示例#8
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;
}
示例#9
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;
}
示例#10
0
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;
}
示例#11
0
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;
}
示例#12
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;
}
示例#13
0
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;
            }
        }
    }
示例#14
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;

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