Hello everyone,

i'm trying to decode my Hevc file in c++ with using FFmpeg. I used Hevc decoder 
and try to save the frames in ppm format. My Hevc file has 677 frames, which i 
checked with ffprobe in command window. But i any got 676 frames with my 
project. Also i have checked with other Hevc files, the results are same, i got 
always one frame less. And i assumed that, that could happy in the position, 
which at last phase i tried to flush the decoder. That means, that could be 3 
frames in the decoder to be flush, but i got only 2 frames.

Can anybody help me, i attach my cpp file and add a link to the whole project 
files. What you need is to define test file path and output directory for saved 
images. Which are for me like that:

D:\Workspace\TestProjects\FFmpegDecoder\TestFiles\sample_1280x720.hevc
D:\Workspace\TestProjects\FFmpegDecoder\Output


Thanks a lot!


Best regards,

Ivan

[https://outlook-2.cdn.office.net/assets/mail/file-icon/png/zip_16x16.png]FFmpegDecoder.zip<https://1drv.ms/u/s!AgIaR65lMcbzgiw7OsY4WG5yVoUV>
#include <iostream>
#include <string>

extern "C"
{
#include "../Headers/libavcodec/avcodec.h"
#include "../Headers/libavformat/avformat.h"
#include "../Headers/libswscale/swscale.h"
}

#define INBUF_SIZE 4096

//Save RGB image as PPM file format
static void ppm_save(char* filename, AVFrame* frame)
{
        FILE* file;
        int i;

        fopen_s(&file, filename, "wb");
        fprintf(file, "P6\n%d %d\n%d\n", frame->width, frame->height, 255);
        for (i = 0; i < frame->height; i++)
                fwrite(frame->data[0] + i * frame->linesize[0], 1, frame->width 
* 3, file);
        fclose(file);
}

void decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt, const char* 
outputDirectory)
{
        char buf[1024];
        int ret;

        ret = avcodec_send_packet(dec_ctx, pkt);
        if (ret < 0) {
                fprintf(stderr, "Error sending a packet for decoding\n");
                exit(1);
        }

        int sts;
        
////////////////////////////////////////////////////////////////////////////
        //Create SWS Context for converting from decode pixel format (like 
YUV420) to RGB
        struct SwsContext* sws_ctx = NULL;
        sws_ctx = sws_getContext(dec_ctx->width,
                dec_ctx->height,
                dec_ctx->pix_fmt,
                dec_ctx->width,
                dec_ctx->height,
                AV_PIX_FMT_RGB24,
                SWS_BICUBIC,
                NULL,
                NULL,
                NULL);

        if (sws_ctx == nullptr)
        {
                return;  //Error!
        }

        //Allocate frame for storing image converted to RGB.
        AVFrame* pRGBFrame = av_frame_alloc();

        pRGBFrame->format = AV_PIX_FMT_RGB24;
        pRGBFrame->width = dec_ctx->width;
        pRGBFrame->height = dec_ctx->height;
        sts = av_frame_get_buffer(pRGBFrame, 0);

        if (sts < 0)
        {
                goto free;
                //return;  //Error!
        }

        while (ret >= 0)
        {
                ret = avcodec_receive_frame(dec_ctx, frame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                        goto free;
                //return;
                else if (ret < 0) {
                        fprintf(stderr, "Error during decoding\n");
                        exit(1);
                }

                //Õý³£Çé¿ö
                printf("saving frame %3d\n", dec_ctx->frame_number);//
                fflush(stdout);

                
//////////////////////////////////////////////////////////////////////////
                //Convert from input format (e.g YUV420) to RGB and save to PPM:
                sts = sws_scale(sws_ctx,    //struct SwsContext* c,
                        frame->data,            //const uint8_t* const 
srcSlice[],
                        frame->linesize,        //const int srcStride[],
                        0,                      //int srcSliceY, 
                        frame->height,          //int srcSliceH,
                        pRGBFrame->data,        //uint8_t* const dst[], 
                        pRGBFrame->linesize);   //const int dstStride[]);

                snprintf(buf, sizeof(buf), "%s\\%s%d.ppm", outputDirectory, 
"Output-", dec_ctx->frame_number);
                ppm_save(buf, pRGBFrame);
        }

free:
        //Free
        
////////////////////////////////////////////////////////////////////////////
        sws_freeContext(sws_ctx);
        av_frame_free(&pRGBFrame);
}

int main(int argc, char** argv)
{
        const char* filename, * outputDirectory, * seqfilename;
        const AVCodec* codec;
        AVCodecParserContext* parser;
        AVCodecContext* codecContext = NULL;
        FILE* file;
        AVFrame* frame;
        uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
        uint8_t* data;
        size_t   data_size;
        int ret;
        AVPacket* pkt;

        std::cout << "Test file full path:";
        std::string inputFilename;

        std::getline(std::cin, inputFilename);
        filename = const_cast<char*>(inputFilename.c_str());

        std::string inputOutput;
        std::cout << "Directory for output images:";
        std::getline(std::cin, inputOutput);
        outputDirectory = const_cast<char*>(inputOutput.c_str());

        pkt = av_packet_alloc();
        if (!pkt)
                exit(1);

        /* set end of buffer to 0 (this ensures that no overreading happens for 
damaged MPEG streams) */
        memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);

        /* find the HEVC video decoder */
        codec = avcodec_find_decoder(AV_CODEC_ID_HEVC);
        if (!codec) {
                fprintf(stderr, "Codec not found\n");
                exit(1);
        }

        parser = av_parser_init(codec->id);
        if (!parser) {
                fprintf(stderr, "parser not found\n");
                exit(1);
        }

        codecContext = avcodec_alloc_context3(codec);
        if (!codecContext) {
                fprintf(stderr, "Could not allocate video codec context\n");
                exit(1);
        }

        /* For some codecs, such as msmpeg4 and mpeg4, width and height
           MUST be initialized there because this information is not
           available in the bitstream. */

           /* open it */
        if (avcodec_open2(codecContext, codec, NULL) < 0) {
                fprintf(stderr, "Could not open codec\n");
                exit(1);
        }

        fopen_s(&file, filename, "rb");
        if (!file) {
                fprintf(stderr, "Could not open %s\n", filename);
                exit(1);
        }

        frame = av_frame_alloc();
        if (!frame) {
                fprintf(stderr, "Could not allocate video frame\n");
                exit(1);
        }

        while (!feof(file)) {
                /* read raw data from the input file */
                data_size = fread(inbuf, 1, INBUF_SIZE, file);
                if (!data_size)
                        break;

                /* use the parser to split the data into frames */
                data = inbuf;
                while (data_size > 0)
                {
                        ret = av_parser_parse2(parser, codecContext, 
&pkt->data, &pkt->size,
                                data, data_size, AV_NOPTS_VALUE, 
AV_NOPTS_VALUE, 0);
                        if (ret < 0) {
                                fprintf(stderr, "Error while parsing\n");
                                exit(1);
                        }
                        data += ret;
                        data_size -= ret;

                        if (pkt->size)
                                decode(codecContext, frame, pkt, 
outputDirectory);
                }
        }

        /* flush the decoder */
        decode(codecContext, frame, NULL, outputDirectory);

        fclose(file);

        av_parser_close(parser);
        avcodec_free_context(&codecContext);
        av_frame_free(&frame);
        av_packet_free(&pkt);

        return 0;
}
_______________________________________________
Libav-user mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Reply via email to