c++libavcodeclibavformatffdshowswscale

AVFrame has a negative linesize


I am using libav (2.7 built for MSVC) to open a camera using dshow:

input_format = av_find_input_format("dshow");
avformat_open_input(format_context, "video=Integrated Camera", input_format, 0);

When I open the video stream it is "raw video" (according to its long_name) in the format AV_PIX_FMT_BGR24. I need to have frames in AV_PIX_FMT_RGB24 so I make a SwsContext as follows:

sws_context = sws_getContext(codec_context->width, codec_context->height, codec_context->pix_fmt, 
                             codec_context->width, codec_context->height, AV_PIX_FMT_RGB24,
                             SWS_BICUBIC, 0, 0, 0);
av_picture = new AVPicture();
avpicture_alloc(av_picture, AV_PIX_FMT_RGB24, codec_context->width, codec_context->height);

I then have a looping timer to read frames and decode into a AVFrame which is then passed off to sws_scale.

while(av_read_frame(format_context, &packet) >= 0)
{
  if(packet.stream_index == stream_index)
  {
    av_frame = 0;
    av_frame = av_frame_alloc();

    avcodec_decode_video2(codec_context, av_frame, &frame_finished, &packet);
    if(frame_finished)
    {
      sws_scale(sws_context, (const uint8_t * const *)av_frame->data, av_frame->linesize,
                0, codec_context->height, av_picture->data, av_picture->linesize);
      av_free_packet(&packet);
      return;
    }
  }
  av_free_packet(&packet);
}

After this point I would use av_picture in my application, however sws_scale hangs and crashes. Looking at all the data I am getting going into sws_scale nothing looks odd to me except the linesize for av_frame. av_frame->linesize[0] == -1920 (linesize[1] and linesize[2] are 0 as expected for BGR24). As the width of my frame is 640 I would expect 1920 but the negative sign seems very odd. I have tried flipping the sign but it does not help. I should note that it does not crash every time (some runs it makes it through a few frames first).

Why would the linesize be negative? Does it mean something or is it just screwed up somehow?


Solution

  • Standard RGB line ordering in Windows for bitmaps and video is bottom-to-top (AFAIR it's only relatively fresh APIs like WIC and Direct2D where line are reordered the natural way). Top-to-bottom order of lines is indicated by negative height and is basically rare. There is nothing wrong with this line order, the pointer to "first pixel" points to leftmost pixel of last row and then you advance between rows by negative offset. libswscale handles this fine.

    Wouldn't a negative linesize correspond with a negative biWidth (which they do not discuss) as opposed to a negative biHeight (which they do)?

    No, the convention is this: if biHeight is negative then it's minus the number of lines and the order of lines is reversed. biWidth is always positive (biWidth is responsible to carry another extension: it might be enlarged to indicated non-standard extended stride in case there is padding to the right from the the payload image).