[Libav-user] MOV/MP4 format not playing in Windows Media Player (but does play in ffplay, vlc, ...)

Robin Stevens rdstevens at gmail.com
Wed Jul 23 11:14:08 CEST 2014


Hi,

I wonder if anyone can help with this, as I've been working on this
problem for a long time now without any progress.

I'm trying to produce an MP4 file with MPEG4p2 video and AAC audio.

The MP4 file is produced, and works just fine in ffplay or vlc, but
won't play in windows media player. (In fact, the audio stream does
play, but not the video.)

If I run the file through ffmpeg.exe -i test.mov -acodec copy -vcodec
copy test2.mov (ie. only remuxing) the resultant file plays fine in
all players.

So, it seems there must be some option that I'm failing to pass to the
muxer to get it to produce compatible files?

When I do a binary compare between the two files, there are only small
differences. The first difference is in the contents of the first
encoded video packet, which has a string like Libavc.63.100 in the bad
file, which has been stripped from the good file.

This data is produced by the video encoder, so is there a setting I
should be passing there?

(I've tried workaround_bugs = FF_BUG_MS, but that value never makes it
to the actual MpegEncContext used internally - please see my other
email. Hacking the ffmpeg code to force the value doesn't seem to make
any difference.)

I'm at my wits end with this; it feels like I'm so close and just need
one crucial piece of information from an expert to finish the job.
Please can anyone here help!!!

The code I'm using is below. I've removed the video signal generation,
error checking and audio generation for brevity. (The problem is the
same whether or not I include an audio stream.)

int main(int argc, char* argv[])
{
  av_register_all();

  AVFormatContext* avFormatContext = NULL;
  AVOutputFormat* avOutputFormat = NULL;

  AVCodecContext* avVideoCodecContext = NULL;
  AVCodec* avVideoCodec = NULL;
  AVStream* avVideoStream = NULL;

  int result = -1;

  const char * filename = "test.mp4";

  avOutputFormat = av_guess_format(NULL, filename, NULL);

  avFormatContext = avformat_alloc_context();
  avFormatContext->oformat = avOutputFormat;
  // Set up the video codec and stream
  avVideoCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);

  AVRational videoTimeBase;
  videoTimeBase.num = 1;
  videoTimeBase.den = 65535;

  AVRational msTimeBase;
  msTimeBase.num = 1;
  msTimeBase.den = 1000;

  avVideoStream = avformat_new_stream(avFormatContext, avVideoCodec);
  avVideoCodecContext = avVideoStream->codec;

  avVideoCodecContext->pix_fmt = PIX_FMT_YUV420P;
  avVideoCodecContext->time_base = videoTimeBase;
  //avVideoCodecContext->strict_std_compliance = 2;
  //avVideoCodecContext->workaround_bugs = FF_BUG_MS; // This doesn't
get copied into   internal private structure.
  // Use opts?
  avVideoCodecContext->width = 640;
  avVideoCodecContext->height = 480;

  result = avcodec_open2(avVideoCodecContext, avVideoCodec, NULL);

  avVideoCodecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;

  // Open the file, into the AVIOContext held in the format context
  result = avio_open(&avFormatContext->pb, filename, AVIO_FLAG_WRITE);

  result = avformat_write_header(avFormatContext, NULL);

  int got_packet_ptr = -1;

  AVPacket videoPacketOut;
  memset(&videoPacketOut, 0, sizeof(AVPacket));


  // Generate an image - removed for brevity


  // Iterate through 60 seconds worth of frames.

  __int64 endPtsMS = 60000; // 60s
  __int64 videoPtsMS = 0LL;

  int desiredFrameCount = 600;
  int calculatedFrameDurationMS = endPtsMS / desiredFrameCount;

  int __i = 0;
  int sampleCount = 0;

  bool moreVideo = true;
  while(moreVideo)
  {
    moreVideo = videoPtsMS < endPtsMS;
    if ((videoPtsMS < endPtsMS) && videoPacketOut.data == 0)
    {
      // BGR24 is a packed format, so all the data is in a single
plane. How do I know this?
      GenerateFrame(sourceFrame, videoPtsMS);

      result = sws_scale(swsContext, sourceFrame->data,
sourceFrame->linesize, 0, sourceHeight, rescaledFrame->data,
rescaledFrame->linesize);


      int64_t videoTimeBasePts = av_rescale_q(videoPtsMS, msTimeBase,
videoTimeBase);
      rescaledFrame->pts = videoTimeBasePts;

      // Compress the video data. libav will allocate the output
buffer, we need to free it
      result = avcodec_encode_video2(avVideoCodecContext,
&videoPacketOut, rescaledFrame, &got_packet_ptr);
      videoPacketOut.stream_index = avVideoStream->index;

    }


    if (videoPacketOut.data != 0 )
    {
      if (videoPacketOut.data != 0)
      {
        result = av_interleaved_write_frame(avFormatContext, &videoPacketOut);

        av_free_packet(&videoPacketOut);
        videoPacketOut.data = 0;
        videoPtsMS += calculatedFrameDurationMS;
      }
    }
  }

  result = av_write_trailer(avFormatContext);

  avcodec_close(avVideoCodecContext);

  avformat_free_context(avFormatContext);
  // todo... more cleaning
  return 0;
}


More information about the Libav-user mailing list