[Libav-user] Using ffmpeg with SDL2 - Bad src image pointers / New decoding flow - questions

Jan jan at dwrox.net
Sun Feb 5 17:07:39 EET 2017


Hello,

Im currently working on a video player software, which should be based 
on ffmpeg tools and at the moment of writing, using SDL2 for display of 
the video content.

The documentation for ffmpeg is a bit difficult to get through, as most 
example code seems to be outdated or using deprecated features.
The SDL tutorial is also not valid anymore, as well as the updated 
version on Github or other information which can be found using a search 
engine of choice.

So I would be glad about assistance.

I seem to struggle at one point: using libswscale's swscale.
I receive the error: "swscaler @ [address] bad src image pointer"

Following parts of the code I use, perhaps the issue is easy to spot?

Also  I am not sure if I use "av_read_frame" and "avcodec_send_packet" 
correctly in the code which should be the new way to go.

I try to set comments where output is displayed. And some in the code.

Following what I have done so far.

The error I get:
[swscaler @ 0x555e2af7ff60] bad src image pointers



//--------------------------------------------------------------------
// Listing of player.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_video.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_render.h>

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include "libavutil/avutil.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"

int main(int argc, char *argv[]) {
 
//----------------------------------------------------------------------------
// SDL
//----------------------------------------------------------------------------

   if (SDL_VideoInit(NULL) != 0) {
     fprintf(stderr, "\nCould not initialize SDL2 video: %s\n", 
SDL_GetError());
     return -1;
   }

   SDL_Window *playerWindow = SDL_CreateWindow("Playerwindow", 
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, 0);
   if (playerWindow == NULL) {
     fprintf(stderr, "\nCould not create application window.\n");
     return -1;
   }
   SDL_Event event;
   SDL_Renderer* gfxRenderer = SDL_CreateRenderer(playerWindow, -1, 
SDL_RENDERER_ACCELERATED);

 
//----------------------------------------------------------------------------
// Init AV backend
//----------------------------------------------------------------------------
   av_register_all();

 
//----------------------------------------------------------------------------
// Video handling
//----------------------------------------------------------------------------

   AVFormatContext *avFormatContext = NULL;
   AVCodecContext *videoCodecContext = NULL;
   AVDictionary *avOptions = NULL;
   AVPacket framePackage;
   AVFrame *videoFrame = NULL;
   AVFrame *videoFrameRGB = NULL;
   AVCodec *videoCodec = NULL;

   if (avformat_open_input(&avFormatContext, "test.avi", NULL, NULL) != 0) {
     fprintf(stderr, "Error opening video file.\n");
     return -1;
   }

   /* retrieve stream information */
   if (avformat_find_stream_info(avFormatContext, NULL) < 0) {
     avformat_close_input(&avFormatContext);
     fprintf(stderr, "No stream information present.\n");
     return -1;
   }

   av_dump_format(avFormatContext, 0, "test.avi", 0);

// Output of av_dump_format (please note that the duration is shown as 
well as the "pix fmt" YUV420P... later on this is not and its enforced!
// Input #0, avi, from 'test.avi':
//  Metadata:
//    encoder         : Lavf57.56.100
//  Duration: 00:08:37.43, start: 0.000000, bitrate: 1081 kb/s
//    Stream #0:0: Video: mpeg4 (Simple Profile) (xvid / 0x64697678), 
yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1075 kb/s, 30 fps, 30 tbr, 30 tbn, 
30 tbc



   int foundStream = av_find_best_stream(avFormatContext, 
AVMEDIA_TYPE_VIDEO, -1, -1, &videoCodec, 0);
   int width = 0;
   int height = 0;

   if (foundStream >= 0) {
     videoCodec = 
avcodec_find_decoder(avFormatContext->streams[foundStream]->codecpar->codec_id);
     videoCodecContext = avcodec_alloc_context3(videoCodec);

     if (avcodec_open2(videoCodecContext, videoCodec, NULL) < 0) {
       fprintf(stderr, "Could not open codec\n");
       return -1;
     }

     // FPS
     int videoFramePerSecond = 
av_q2d(avFormatContext->streams[foundStream]->r_frame_rate);
     // Base time unit
     int videoBaseTime = 
av_q2d(avFormatContext->streams[foundStream]->time_base);
     // Duration of video clip
     unsigned long videoDuration = (unsigned long) 
avFormatContext->streams[foundStream]->duration * (videoFramePerSecond * 
videoBaseTime);
     // Frame width
     width = avFormatContext->streams[foundStream]->codecpar->width;
     // Frame height
     height = avFormatContext->streams[foundStream]->codecpar->height;

     printf("fps: %d, basetime: %d, duration: %ld, width: %d, height: 
%d\n", videoFramePerSecond, videoBaseTime, videoDuration, width, height);

// Output:
// fps: 30, basetime: 0, duration: 0, width: 1280, height: 720


     printf("inside - pix format : %d\n", videoCodecContext->pix_fmt);

// Output:
// inside - pix format : -1 (why -1 ?, should this not be in line with 
the av_dump_format output?)

     struct SwsContext *sws_context = NULL;
     sws_context = sws_getContext(width, height, AV_PIX_FMT_YUV420P, 
width, height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);

     videoFrame = av_frame_alloc();
     videoFrameRGB = av_frame_alloc();

     //avcodec_align_dimensions(videoCodecContext, &width, &height); // 
this always crashes

     videoFrameRGB->format = AV_PIX_FMT_RGB24;
     videoFrameRGB->width = width;
     videoFrameRGB->height = height;
     printf("buffer allocated: %d\n",av_frame_get_buffer(videoFrameRGB, 
AV_INPUT_BUFFER_PADDING_SIZE));
// Output:
// buffer allocated: 0


     printf("made writeable: %d\n", av_frame_make_writable(videoFrameRGB));
// Output:
// made writeable: 0


     printf("is writeable: %d\n", av_frame_is_writable(videoFrameRGB));
// Output:
// is writeable: 1


     av_init_packet(&framePackage);

     int frameIndex = 1;
     framePackage.data = NULL; // packet data will be allocated by the 
encoder
     framePackage.size = 0;

     // SDL
     SDL_Rect displayRect = {0, 0, width, height};
     SDL_Texture *videoTexture = SDL_CreateTexture(gfxRenderer, 
SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 
videoCodecContext->width, videoCodecContext->height);
     //----------------------------------------------------------------

     while (av_read_frame(avFormatContext, &framePackage) == 0) {

       if (framePackage.stream_index == foundStream) {
         int retVal = avcodec_send_packet(videoCodecContext, &framePackage);
         if (retVal == 0) {
           printf("Success\n");
// Outputs success, so the frame should be read as displayable?
         } else {
           printf("%s\n", av_err2str(retVal));
           continue;
         }

         printf("Frame #%8d | pts: %ld | dts: %ld | size: %10d | 
stream_index: %d | flags: %d | duration: %ld | pos: %ld\n",
           frameIndex,
           framePackage.pts, framePackage.dts, framePackage.size,
           framePackage.stream_index, framePackage.flags,
           framePackage.duration, framePackage.pos
         );

         videoFrame->width = width;
         videoFrame->height = height;

         videoFrameRGB->format = AV_PIX_FMT_RGB24;
         videoFrameRGB->width = width;
         videoFrameRGB->height = height;
         printf("width: %d, height: %d\n", width, height);
         av_frame_get_buffer(videoFrameRGB, AV_INPUT_BUFFER_PADDING_SIZE);
         sws_getCachedContext(sws_context, width, height, 
AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, 
NULL, NULL, NULL);
         printf("%d\n", sws_scale(sws_context, (const uint8_t * const *) 
videoFrame->data, videoFrame->linesize, 0, height, videoFrameRGB->data, 
videoFrameRGB->linesize));
         SDL_RenderClear(gfxRenderer);
         SDL_UpdateTexture(videoTexture, NULL, videoFrameRGB->data, 
videoFrameRGB->linesize[0]);
         SDL_RenderCopy(gfxRenderer, videoTexture, NULL, &displayRect);
         SDL_RenderPresent(gfxRenderer);
         SDL_Delay(1000 / 25);
         bool doQuit = false;
         while (SDL_PollEvent(&event)) {
           switch (event.type) {
             case SDL_QUIT:
               doQuit = true;
               break;
             default:
               break;
           }
         }

         avcodec_send_packet(videoCodecContext, NULL);

         if (doQuit) {
           break;
         }

         ++frameIndex;

         av_frame_unref(videoFrameRGB);
         av_frame_unref(videoFrame);
       }

       avcodec_flush_buffers(videoCodecContext);
     }
     //av_free_packet(&framePackage);
     SDL_DestroyTexture(videoTexture);
   }

   // Cleanup video
   av_packet_unref(&framePackage);
   av_frame_free(&videoFrame);
   av_frame_free(&videoFrameRGB);

   // Cleanup ffmpeg components
   av_dict_free(&avOptions);
   avformat_close_input(&avFormatContext);

   // Cleanup SDL
   SDL_DestroyRenderer(gfxRenderer);
   SDL_DestroyWindow(playerWindow);

   printf("Done.\n");
   return 0;
}

//----------------------------------------------------------------


What am I missing out here, the alignment?

If you need any other information, please let me know.
Thank you for any help in advance.

Jan


More information about the Libav-user mailing list