[FFmpeg-devel] using usb hardware h264 encoders

Michael Niedermayer michaelni
Thu Nov 11 13:52:37 CET 2010


On Fri, Apr 16, 2010 at 07:58:24PM +0300, Sergiy wrote:
> Hi all
> 
> As i said before, now encoder accepts NV12 natively.
> 

> Long time I'd tried to understand why PTS wrapping does not works, but seems
> it's known ffmpeg's issue,

which issue on roundup is it?


[...]
> +/* parse first 6x4 bytes of header
> + * TODO: parse headers with extensions (may be longer)
> + *
> + */

not doxy compatible


> +int ff_qbox_parse(qboxContext *qbox, uint8_t *input_data, int data_size)
> +{
> +    const uint8_t *src = input_data;
> +
> +    if(data_size < QBOX_HDR_SIZE)
> +        return 0;
> +
> +
> +    qbox->qbox_size = bytestream_get_be32(&src);
> +    if(qbox->qbox_size < QBOX_HDR_SIZE)
> +        return 0;
> +
> +    qbox->qbox_size-=QBOX_HDR_SIZE;

> +    bytestream_get_be32(&src); //qbox
> +    qbox->version = bytestream_get_byte(&src);
> +    qbox->boxflags = bytestream_get_be24(&src);
> +    qbox->sample_stream_type = bytestream_get_be16(&src);
> +    qbox->sample_stream_id = bytestream_get_be16(&src);
> +    qbox->sample_flags = bytestream_get_be32(&src);
> +    qbox->sample_cts = bytestream_get_be32(&src);

vertical align


[...]
> +
> +
> +/*
> + * demuxer probe:
> + * first 4 bytes of every qbox - is full qbox length
> + * next 4 bytes - chars "qbox", try find them
> + */

missing /**

also please try tools/patcheck


[...]
> +/*
> + * extradata set, create packets from qboxes
> + * */
> +static int qbox_read_packet(AVFormatContext *s, AVPacket *pkt) {
> +    qboxDemux *d = s->priv_data;
> +    qboxContext *c = &d->qbox;
> +    ByteIOContext *pb = s->pb;
> +    uint8_t qbox_header[QBOX_HDR_SIZE];
> +    int ret = 0;
> +
> +    if(!d->from_header) {
> +        if(!get_buffer(pb, qbox_header, QBOX_HDR_SIZE))
> +            return AVERROR(EIO);
> +
> +        if(!ff_qbox_parse(c, qbox_header, QBOX_HDR_SIZE))
> +            return AVERROR(EIO);
> +    } else {
> +        d->from_header=0;
> +    }
> +#ifdef QBOX_EXTRA_DEBUG
> +    av_log(s, AV_LOG_DEBUG, "qbox: s:%d t:0x%08x id:%08x f:%08x cts:%d\n",
> +            c->qbox_size, c->sample_stream_type, c->sample_stream_id, c->sample_flags, c->sample_cts);
> +#endif
> +
> +    if ((ret = av_get_packet(pb, pkt, c->qbox_size)) <= 0)
> +        return AVERROR(EIO);
> +
> +    pkt->dts = c->sample_cts;
> +    if(c->sample_flags & SAMPLE_FLAGS_SYNC_POINT)
> +        pkt->flags |= PKT_FLAG_KEY;
> +
> +
> +    switch (c->sample_stream_type) {
> +        case SAMPLE_TYPE_QMA:
> +        case SAMPLE_TYPE_PCM:
> +        case SAMPLE_TYPE_AAC:
> +            pkt->stream_index = 1;
> +            break;
> +        case SAMPLE_TYPE_H264:
> +            pkt->stream_index = 0;

missing checks that these streams exist at all


[...]
> +enum {
> +    SAMPLE_TYPE_AAC = 0x1,
> +    SAMPLE_TYPE_H264,
> +    SAMPLE_TYPE_PCM,
> +    SAMPLE_TYPE_DEBUG,
> +    SAMPLE_TYPE_H264_SLICE,
> +    SAMPLE_TYPE_QMA,
> +    SAMPLE_TYPE_VIN_STATS_GLOBAL,
> +    SAMPLE_TYPE_VIN_STATS_MB,
> +    SAMPLE_TYPE_Q711,
> +    SAMPLE_TYPE_Q728,
> +    SAMPLE_TYPE_MAX,
> +};

the enum should be named and the type should then be used


[...]
> +/** parse every qbox, received from codec, when have "flush" event
> + */
> +static int add_nals(AVCodecContext *ctx, int alloc_buff)
> +{
> +    CrusherEncContext *c4 = ctx->priv_data;
> +    qboxContext qbox;
> +    int i;
> +    int oldptr = c4->frames_buff_fill;
> +
> +    if(!c4->enc.out_blocks)
> +        return 0;
> +
> +    /* in most cases we have 6 qboxes at one event */
> +    for(i=c4->curr_block; i < c4->enc.out_blocks; i++) {
> +        if(ff_qbox_parse(&qbox, c4->enc.out_data[i].data, c4->enc.out_data[i].len)) {
> +#ifdef CRUSHER_EXTRA_DEBUG
> +            av_log(ctx, AV_LOG_DEBUG, "QBOX: sst:0x%08x sf:0x%08x l:%d ts:%d\n",
> +                    qbox.sample_stream_type, qbox.sample_flags, qbox.qbox_size, qbox.sample_cts);
> +#endif
> +            if(qbox.sample_stream_type != SAMPLE_TYPE_H264) {
> +                av_log(ctx, AV_LOG_ERROR, "Unknown sample flags 0x%08x (maybe audio?)\n", qbox.sample_flags);
> +                return -1;
> +            }
> +
> +            if(!ff_qbox_make_startcode(qbox.data, qbox.qbox_size)){
> +                av_log(ctx, AV_LOG_ERROR, "can't create H264 startcodes\n");
> +                return -1;
> +            }
> +
> +            /* payload started ? */
> +            if(qbox.sample_flags & SAMPLE_FLAGS_CONFIGURATION_INFO) {
> +                if(alloc_buff) {
> +                    c4->sps_pps_size = qbox.qbox_size;
> +                    c4->sps_pps = av_malloc(c4->sps_pps_size);
> +                    memcpy(c4->sps_pps, qbox.data, c4->sps_pps_size);
> +                } else {
> +                    av_log(ctx, AV_LOG_ERROR, "SPS/PPS received in the middle of encoding\n");
> +                }
> +            } else {
> +                if(c4->frames_buff_skip) {
> +                    c4->frames_buff_skip--;
> +                    continue;
> +                }
> +                if(c4->frames_buff_fill == c4->frames_buff_size) {
> +                    if(alloc_buff) {
> +                        c4->frames_buff_size++;
> +                        c4->frames_buff = av_realloc(c4->frames_buff, sizeof(qboxContext) * c4->frames_buff_size);

missing check for malloc fail


[...]
> +/** encode 1 frame
> + */
> +static int CrusherEnc_frame(AVCodecContext *ctx, uint8_t *buf,
> +                                int bufsize, void *data)
> +{
> +    CrusherEncContext *c4 = ctx->priv_data;
> +    AVFrame *frame = data;
> +    int ret = -1;
> +    int datalen = 0;
> +
> +    assert(ctx->pix_fmt == PIX_FMT_NV12);
> +
> +    if(frame) {

> +        /* canvas size & copy frame
> +         * can't use av_picture_copy due uv width must be equal y width */
> +        ff_img_copy_plane(c4->conv_input.data[0], c4->conv_input.linesize[0],
> +                frame->data[0], frame->linesize[0], ctx->width, ctx->height);
> +        ff_img_copy_plane(c4->conv_input.data[1], c4->conv_input.linesize[1],
> +                frame->data[1], frame->linesize[1], ctx->width, ctx->height>>1);
> +
> +        /* Convert planes to the crusher format (sequence of 32x16 blocks in NV12 format) */
> +        conv_frame(c4);

you copy data twice, thats surely not needed



> +        do  {
> +            ret = crusher_encode(&c4->enc, c4->conv_output.data[0], c4->enc.inputFrameLen);
> +            if(ret == CODEC_FLUSHED)
> +                add_nals(ctx, 0);
> +        } while (ret == CODEC_FLUSHED);
> +    } else if(!c4->enc.finished) {
> +        av_log(ctx, AV_LOG_DEBUG, "Codec finishing!\n");
> +        do {
> +            ret = crusher_encode(&c4->enc, NULL, 0);
> +            if (ret == CODEC_FLUSHED)
> +                add_nals(ctx, 0);
> +        } while(ret != CODEC_FAIL && ret != CODEC_FINISHED);
> +    }
> +
> +    if(ret == CODEC_FAIL) {
> +        av_log(ctx, AV_LOG_ERROR, "Failed\n");
> +        return -1;
> +    }
> +
> +    /* send frame from buffer */
> +    if(c4->frames_buff_fill) {
> +        assert(bufsize >= c4->frames_buff[0].size);
> +#ifdef CRUSHER_EXTRA_DEBUG
> +        av_log(ctx, AV_LOG_DEBUG, "Frame out[0/%d/%d]:"
> +                                  "len:%d, type:%d, ts:%d\n",
> +                c4->frames_buff_fill, c4->frames_buff_size,
> +                c4->frames_buff[0].qbox_size,
> +                c4->frames_buff[0].sample_stream_type,
> +                c4->frames_buff[0].sample_cts);
> +#endif
> +        datalen = c4->frames_buff[0].qbox_size;
> +        memcpy(buf, c4->frames_buff[0].data, datalen);
> +        av_freep(&c4->frames_buff[0].data);
> +
> +        if(c4->frames_buff[0].sample_flags & SAMPLE_FLAGS_SYNC_POINT) {
> +            ctx->coded_frame->key_frame = 1;
> +            ctx->coded_frame->pict_type = FF_I_TYPE;
> +        } else {
> +            ctx->coded_frame->key_frame = 0;
> +            ctx->coded_frame->pict_type = FF_P_TYPE;
> +        }
> +        //just return number of frame?
> +        if (c4->frames_buff[0].sample_flags & SAMPLE_FLAGS_CTS_PRESENT) {

> +            ctx->coded_frame->pts = c4->frames_buff[0].sample_cts/c4->enc.framerate_den - c4->frames_delay;

the division looks strange


[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Many things microsoft did are stupid, but not doing something just because
microsoft did it is even more stupid. If everything ms did were stupid they
would be bankrupt already.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20101111/9d2e7a9f/attachment.pgp>



More information about the ffmpeg-devel mailing list