[Libav-user] Custom data in AVPacket or AVFrame

laddoe xyfix at hotmail.com
Wed Feb 16 17:38:12 EET 2022


Hi Brad,

I tried your example but I could not see the data that I added as side data. This is my code ( simplified and only relevant parts ),  please let me know if you need more. The image class has a OpenCV Mat and some members. In the encoder I see the char that I added as side_data to the frame, but it can't be retrieved when I decode it. I want to mention again that encode/decoding works like a charm.... but not the custom side data 🙁

=====================================================
void MovieEncoder::process(const std::vector< Image >* images )
{
TimeStamp encodingTimer("EncodingTimer", true );

    for( auto image : *images )
    {
        if( m_setStartTime )
        {
            m_startTime = image.timeStamp();
            m_setStartTime = false;
        }


        if (!m_stream )
           return;

        AVFrame* frame = av_frame_alloc();

        createFrame( image, frame );

        writeFrame( frame );

        if( frame )
        {
            av_free( frame->data[0]);
            av_frame_free( &frame );
        }
    }
}

=====================================================
 void MovieEncoder::createFrame( const Image& image, AVFrame* frame )
{
    frame->format = outputPixelFormat;
    frame->width = image.width();
    frame->height = image.height();
    frame->pict_type = AV_PICTURE_TYPE_P;

    int ret = av_image_alloc( frame->data, frame->linesize, frame->width,  frame->height, AV_PIX_FMT_BGR24, 1);

    if (ret < 0)
        return;

    struct SwsContext* sws_ctx = sws_getContext((int)image.width(), (int)image.height(), AV_PIX_FMT_BGR24,
                                                (int)image.width(), (int)image.height(), outputPixelFormat,
                                                0, NULL, NULL, NULL);

    const uint8_t* rgbData[1] = { (uint8_t* )image.getData() };
    int rgbLineSize[1] = { 3 * (int)image.width() };

    sws_scale(sws_ctx, rgbData, rgbLineSize, 0, image.height(), frame->data, frame->linesize);

    // @Brad, just adding a char 'H' here
    char seiMessage[] = {'H'};
    qDebug() << "encode " << seiMessage;
    AVFrameSideData* sideData = av_frame_new_side_data( frame, AV_FRAME_DATA_SEI_UNREGISTERED, sizeof( seiMessage ));
    if( sideData == nullptr )
        return;
    std::memcpy( sideData->data, seiMessage, sideData->size );
    qDebug() << "encode side " << *( char*)( sideData->data );
}

=====================================================
void MovieEncoder::encodingFrame( AVFrame* frame )
{
    int result;

    if ( s_frameCount >= streamNumberOfFrames)
    {
        /**
         * @note No more frames to compress.
         */
        s_frameCount = streamNumberOfFrames;
    }

    frame->pts = s_frameCount;


    if (m_formatCtx->oformat->flags & AVFMT_NOFILE )
    {
        /**
         * @todo this is experimental for other examinations than OSV/OSD
         * @note Raw video case - directly store the picture in the packet
         */
        AVPacket pkt;
        av_init_packet(&pkt);

        pkt.flags |= AV_PKT_FLAG_KEY;
        pkt.stream_index = m_stream->index;
        pkt.data = frame->data[0];
        pkt.size = sizeof(AVPicture);

        result = av_write_frame( m_formatCtx, &pkt );
    }
    else
    {
        AVPacket pkt;
        av_init_packet(&pkt);

        result = avcodec_send_frame(m_codecCtx, frame);

        checkError( result, "Error encoding video frame: ");

        while( result >= 0 )
        {
            result = avcodec_receive_packet(m_codecCtx, &pkt);

            if (result == AVERROR(EAGAIN) /*|| ret == AVERROR_EOF*/)
            {
                Log::printLine("No more packet to write", Log::Debug );
                return;
            }
            else if (result < 0)
            {
                  Log::printLine("Codec context of the package is not correct", Log::Debug);
                  return;
            }

            pkt.stream_index = m_stream->index;

            pkt.pts = av_rescale_q( pkt.pts, m_codecCtx->time_base, m_stream->time_base );
            pkt.dts = av_rescale_q( pkt.dts, m_codecCtx->time_base, m_stream->time_base );
            pkt.duration = int64( 1 / streamFrameRate );

            result = av_write_frame( m_formatCtx, &pkt );

            s_frameCount++;
        }
    }
}


=====================================================
void MovieDecoder::process()
{
    int retCode( 0 );

    AVFrame *frame = av_frame_alloc();
    AVFrame* rgbFrame = av_frame_alloc();
    AVPacket* avpkt = av_packet_alloc();

    uint8_t* imageBuffer = NULL;

    // Read all the frames
    while( av_read_frame( m_formatCtx, avpkt ) >= 0)
    {
        if (avpkt->size == 0)
          break;

        // This function might fail because of parameter set packets, just ignore and continue
        retCode = avcodec_send_packet( m_codecCtx, avpkt);
        checkError( retCode, "avcodec_send_packet ret < 0" );

        if (retCode < 0)
            continue;


        // Receive the uncompressed frame back
        retCode = avcodec_receive_frame( m_codecCtx, frame);

        // @Brad, no char 'H' found over here 🙁
        AVFrameSideData* sideData = av_frame_get_side_data( frame, AV_FRAME_DATA_SEI_UNREGISTERED );
        qDebug() << "decode " << *(char*)sideData->data;

        if (retCode < 0)
        {
          // Sometimes we cannot get a new frame, continue in this case
          if (retCode == AVERROR(EAGAIN))
              continue;

           break;
        }

        // Calculate output buffer requirements
        uint32_t bufferSize = av_image_get_buffer_size(AVPixelFormat(frame->format),
                                                              frame->width, frame->height, 1);

        // Use temp buffer for the video data
        if( imageBuffer == NULL )
            imageBuffer = new uint8_t[bufferSize];


        struct SwsContext* sws_ctx = sws_getContext((int)frame->width, (int)frame->height, AV_PIX_FMT_GBRP,
                                                    (int)frame->width, (int)frame->height, inputPixelFormat,
                                                     NULL, NULL, NULL, NULL);

        av_image_fill_arrays( rgbFrame->data, rgbFrame->linesize, imageBuffer,
                              inputPixelFormat, m_codecCtx->width, m_codecCtx->height, 1);

        rgbFrame->width = m_codecCtx->width;
        rgbFrame->height = m_codecCtx->height;
        rgbFrame->format = inputPixelFormat;

        sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, rgbFrame->data, rgbFrame->linesize );

        cv::Mat rgbMat( frame->height, frame->width, CV_8UC3, rgbFrame->data[0] );

        av_packet_unref( avpkt );
    }

    delete imageBuffer;

    avcodec_close( m_codecCtx );
    av_free( m_codecCtx );
    av_dict_free(&frame->metadata);
    av_frame_free( &frame );
    av_frame_free( &rgbFrame );
    av_packet_free( &avpkt );
}
________________________________
Van: Libav-user <libav-user-bounces at ffmpeg.org> namens laddoe <xyfix at hotmail.com>
Verzonden: woensdag 16 februari 2022 12:24
Aan: This list is about using libavcodec, libavformat, libavutil, libavdevice and libavfilter. <libav-user at ffmpeg.org>
Onderwerp: Re: [Libav-user] Custom data in AVPacket or AVFrame

Sorry that was my fault but I use avcodec-58.dll, avformat-58.dll, avutil-56.dll and libx264-161.dll. I will try your example code and come back to you.
________________________________
Van: Libav-user <libav-user-bounces at ffmpeg.org> namens Brad Hards <bradh at frogmouth.net>
Verzonden: woensdag 16 februari 2022 10:28
Aan: This list is about using libavcodec, libavformat, libavutil, libavdevice and libavfilter. <libav-user at ffmpeg.org>
Onderwerp: Re: [Libav-user] Custom data in AVPacket or AVFrame

On Wednesday, 16 February 2022 8:16:17 PM AEDT laddoe wrote:
> Correction, I meant av_frame_new_side_data but it looks like the "side data"
> is not meant for that. I couldn't find the right documentation that would
> explain what the purpose is for the "side data" ( the same for
> AVPacketSideData). I also tried the metadata struct (AVDictionary) in the
> AVFrame struct but it did not work either.
We know it didn't work - you wouldn't be posting if it did.
However we have no idea what actually happened instead. We still don't know
what version of the libraries you are using.

Here is an extract from a sample I used:

    AVFrame *frame;
    AVFrameSideData *side_data;
    // This is from MISB ST 2101
    char sei_message[] = {0xa5, 0x50, 0x52, 0xaf, 0x52, 0x16, 0x5f, 0x45,
                          0xa3, 0x18, 0x1c, 0xfc, 0x7a, 0xbb, 0xc2, 0x67,
                          0x01, 0x70, 0xF5, 0x92, 0xF0, 0x23, 0x73, 0x36,
                          0x4A, 0xF8, 0xAA, 0x91, 0x62, 0xC0, 0x0F, 0x2E,
                          0xB2, 0xDA, 0x16, 0xB7, 0x43, 0x41, 0x00, 0x08,
                          0x41, 0xA0, 0xBE, 0x36, 0x5B, 0x5A, 0xB9, 0x6A,
                          0x36, 0x45};

    side_data = av_frame_new_side_data(frame, AV_FRAME_DATA_SEI_UNREGISTERED,
sizeof(sei_message));
    if (!side_data)
    {
        fprintf(stderr, "Could not allocate the video frame side data\n");
        exit(1);
    }
    memcpy(side_data->data, sei_message, side_data->size);

If that doesn't work for you, please make a SSCCE (http://sscce.org/) of what
you are doing, what you expected that code to do, and what happened instead.

Brad



_______________________________________________
Libav-user mailing list
Libav-user at ffmpeg.org
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
libav-user-request at ffmpeg.org with subject "unsubscribe".
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://ffmpeg.org/pipermail/libav-user/attachments/20220216/d35688ea/attachment.htm>


More information about the Libav-user mailing list