Opened 4 years ago

Closed 4 years ago

#4404 closed defect (invalid)

Cannot decode PNG or TIF files with libavcodec.

Reported by: sgan Owned by:
Priority: normal Component: avcodec
Version: unspecified Keywords: PNG avcodec_decode_video2
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:
With libavcodec dlls, I cannot decode .PNG or .TIF files format but it is working fine with .JPEG or .BMP files.
Remark: with ffmpeg.exe, I am able to decode/encode these files (-i input.png -pix_fmt rgb32 output.bmp)
How to reproduce:

I am using latest dll provided by Zeranoe FFmpeg:
Build Version: git-cf16b45 (2015-03-29)
libavutil      54. 20.101 / 54. 20.101
libavcodec     56. 31.100 / 56. 31.100
libavformat    56. 26.101 / 56. 26.101
libavdevice    56.  4.100 / 56.  4.100
libavfilter     5. 13.101 /  5. 13.101
libswscale      3.  1.101 /  3.  1.101
libswresample   1.  1.100 /  1.  1.100
libpostproc    53.  3.100 / 53.  3.100

I am just testing the following code with a .png file:
http://ffmpeg.org/doxygen/trunk/lavfutils_8c_source.html#l00024

Problem:
At line 77
ret = avcodec_decode_video2(codec_ctx, frame, &frame_decoded, &pkt);

ret is >0 and is equal to PNG file size, but frame_decoded=0!!
AVFrame *frame;

According to documentation:
http://ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga99ee61b6dcffb7817a275d39da58cc74
"

  • got_picture_ptr: Zero if no frame could be decompressed, otherwise, it is nonzero.
  • Returns: On error a negative value is returned, otherwise the number of bytes used or zero if no frame could be decompressed."

In our case, we have at the same time :

  • got_picture_ptr=0
  • Returns=number of bytes used

It seems incompatible.

As said, the code is working fine with jpeg or bmp files.
Problem occurs on 32 or 64 bits dll.

Attachments (1)

15x2Mire.png (230 bytes) - added by sgan 4 years ago.
Example of png file.

Download all attachments as: .zip

Change History (4)

Changed 4 years ago by sgan

Example of png file.

comment:1 Changed 4 years ago by sgan

So I am still working on it and I think I finally found the solution.

As I am not an libavcodec expert, please fill free to comment.

According to avcodec_open2 documentation,
http://ffmpeg.org/doxygen/trunk/group__lavc__core.html#ga11f785a188d7d9df71621001465b0f1d
Prior to using this function the context has to be allocated with avcodec_alloc_context3().

So new code should be something like that (modifications have been commented as [sgan]:

int ff_load_image(uint8_t *data[4], int linesize[4],
                  int *w, int *h, enum AVPixelFormat *pix_fmt,
                  const char *filename, void *log_ctx)
{
    AVInputFormat *iformat = NULL;
    AVFormatContext *format_ctx = NULL;
    AVCodec *codec;
    AVCodecContext *codec_ctx;
    AVFrame *frame;
    int frame_decoded, ret = 0;
    AVPacket pkt;

    av_init_packet(&pkt);

    av_register_all();

    iformat = av_find_input_format("image2");
    if ((ret = avformat_open_input(&format_ctx, filename, iformat, NULL)) < 0) {
        av_log(log_ctx, AV_LOG_ERROR,
               "Failed to open input file '%s'\n", filename);
        return ret;
    }

    if ((ret = avformat_find_stream_info(format_ctx, NULL)) < 0) {
        av_log(log_ctx, AV_LOG_ERROR, "Find stream info failed\n");
        return ret;
    }

    //codec_ctx = format_ctx->streams[0]->codec;            //[sgan]To remove
    codec = avcodec_find_decoder(codec_ctx->codec_id);   //[sgan]To modify 
    if (!codec) {
        av_log(log_ctx, AV_LOG_ERROR, "Failed to find codec\n");
        ret = AVERROR(EINVAL);
        goto end;
    }
    
    codec_ctx = avcodec_alloc_context3(codec);   //[sgan]To add
      if (!codec_ctx) return -1;                           //[sgan]To add

   
   codec_ctx->width=format_ctx->streams[0]->codec->width;         //[sgan]To add
   codec_ctx->height=format_ctx->streams[0]->codec->height;      //[sgan]To add
   codec_ctx->pix_fmt=format_ctx->streams[0]->codec->pix_fmt;   //[sgan]To add

    if ((ret = avcodec_open2(codec_ctx, codec, NULL)) < 0) {
        av_log(log_ctx, AV_LOG_ERROR, "Failed to open codec\n");
        goto end;
    }

    if (!(frame = av_frame_alloc()) ) {
        av_log(log_ctx, AV_LOG_ERROR, "Failed to alloc frame\n");
        ret = AVERROR(ENOMEM);
        goto end;
    }

    ret = av_read_frame(format_ctx, &pkt);
    if (ret < 0) {
        av_log(log_ctx, AV_LOG_ERROR, "Failed to read frame from file\n");
        goto end;
    }

    ret = avcodec_decode_video2(codec_ctx, frame, &frame_decoded, &pkt);
    if (ret < 0 || !frame_decoded) {
        av_log(log_ctx, AV_LOG_ERROR, "Failed to decode image from file\n");
        if (ret >= 0)
            ret = -1;
        goto end;
    }

    *w       = frame->width;
    *h       = frame->height;
    *pix_fmt = frame->format;

    if ((ret = av_image_alloc(data, linesize, *w, *h, *pix_fmt, 16)) < 0)
        goto end;
    ret = 0;

    av_image_copy(data, linesize, (const uint8_t **)frame->data, frame->linesize, *pix_fmt, *w, *h);

end:
    av_free_packet(&pkt);
    //avcodec_close(codec_ctx);               //[sgan]To remove
    avcodec_free_context(&codec_ctx);      //[sgan]To add
    avformat_close_input(&format_ctx);
    av_frame_free(&frame);

    if (ret < 0)
        av_log(log_ctx, AV_LOG_ERROR, "Error loading image file '%s'\n", filename);
    return ret;
}

It seems that after:

 codec_ctx = avcodec_alloc_context3(codec);

, some attibutes have to be set (width,height, ...).

Now it is working with PNG and TIFF files also.

comment:2 Changed 4 years ago by sgan

I am following investigations!!

In fact, the original code http://ffmpeg.org/doxygen/trunk/lavfutils_8c_source.html#l00024 is working for PNG if we set the AVCodecContext::thread_count attribute to 1.

ex at line 59: format_ctx->streams[0]->codec->thread_count=1;

This is a workaround and I do not know why it is working. Problem should be analyse now deeply by developers.

The problem is connected to the following point:
http://stackoverflow.com/questions/22930109/call-to-avformat-find-stream-info-prevents-decoding-of-simple-png-image/22994263#22994263

Regards

Sebastien.

comment:3 Changed 4 years ago by michael

  • Resolution set to invalid
  • Status changed from new to closed

Yes, thread_count has to be set to 1 or the user application must call the decoder in a loop until the frame has been decoded.

Note: See TracTickets for help on using tickets.