locked
The MP4 which created by IMFSinkWriter on win8 winRT cannot play on win7!

    Question

  • Dear all:

    I write a MP4 video with IMFSinkWriter, it can play with mediaplay on win8 and video app in win8 app store. but it cannot be played on the win7 with mediaplay and pureplayer. Is it the  IMFSinkWriter winRT's Bug?

    Does anyone know about it?

    Monday, May 13, 2013 2:54 AM

All replies

  • Hello,

    It is difficult to say why this might be happening. It is possible that you are not setting up the codec properly. If you can provide a file the reproduces the problem I can run the file through our h.264 verification tools and possibly tell you what is happening. Please place the file on your SkyDrive and post a link here.

    Thanks,

    James


    Windows SDK Technologies - Microsoft Developer Services - http://blogs.msdn.com/mediasdkstuff/

    Monday, May 13, 2013 9:56 PM
    Moderator
  • Dear James:

    the sample video is put here.

    https://skydrive.live.com/redir?resid=145394061DFAE418!107&authkey=!AOdJre3AmSRnIX0

    Wednesday, May 15, 2013 7:27 AM
  • Hi, I'm having exactly the same problem with MP4 generated using IMFSinkWriter under Win8. Does anyone have any update for this thread?

    Thanks!

    Wednesday, June 25, 2014 10:58 AM
  • Check whether the file is a fragmented mp4.  I think fragmented MP4 support was added in Win8 and hence this file won’t play on Win7. You create a fragmented mp4 using either

    MFTranscodeContainerType_FMPEG4

    OR

    MFCreateFMPEG4MediaSink

    Monday, June 30, 2014 6:12 PM
  • Checked codec info with VLC, it says video codec is MPEG-4 AVC part 10, so this is not a fragmented MPEG. Nothing special, except FPS = 2.

    In my project i'm using IMFSinkWriter too, but have no problems with playing encoded video on windows 7. How do you initializing your sink writer, did you setted up subType, bitRate other codec stuffs correctly?

    Monday, June 30, 2014 9:11 PM
  • For Yixiong's content, shared via OneDrive link above, the file is definitely fMP4.  It contains both moof and mfra boxes, and has the classic fMP4 file layout. Yixiong, can try to set the output format to normal MP4 for best interoperability with all platforms and players.  Given that part of the thread is a year old, I suspect it's been worked out.

    Paro77, we'll probably need a bit more information to help you.  What options are you setting on the IMFSinkWriter?  Can you share code or an output file?

    Ref: http://msdn.microsoft.com/en-us/library/windows/desktop/ff819489(v=vs.85).aspx

    Thanks,

    -Nick

    Monday, June 30, 2014 9:32 PM
  • Hi Nick,

    Yes, here is demo code in C# that outputs the MP4 in question:

        internal class Demo
        {
            private IMFByteStream _byteStream;
            private IMFMediaType _mediaType;
            private IMFSinkWriter _sinkWriter;
            private IMFMediaSink _mediaSink;
            private ulong _frameDuration;
    
            // pFrames contains the H264 frames as binaries
            public void Mux(List<byte[]> pFrames)
            {
                // Start Media Foundation:
                MFHelper.MFStartup();
    
                // Calculate average frame duration, in HNS, given a 10fps input:
                double duration = (1 / 10F) * 10000000;
                _frameDuration = (ulong)duration;
    
                // Set up input media type object:
                _mediaType = MFHelper.MFCreateMediaType();
    
                _mediaType.SetGUID(Constants.MF_MT_MAJOR_TYPE, Constants.MFMediaType_Video);
                _mediaType.SetGUID(Constants.MF_MT_SUBTYPE, Constants.MFVideoFormat_H264);
    
                _mediaType.SetUINT32(Constants.MF_MT_INTERLACE_MODE, (uint)(MFVideoInterlaceMode.MFVideoInterlace_Progressive));
    
                _mediaType.SetUINT64(Constants.MF_MT_FRAME_SIZE, MFHelper.Pack((uint)1920, (uint)1080));
                _mediaType.SetUINT64(Constants.MF_MT_FRAME_RATE, MFHelper.Pack((uint)10, (uint)1)); // The input is a GOP of 10 frames, 1 second long
                _mediaType.SetUINT64(Constants.MF_MT_PIXEL_ASPECT_RATIO, MFHelper.Pack((uint)1, (uint)1));
    
                // Initialize media sink and output file/stream:
                string filename = "output.mp4";
                _byteStream = MFHelper.MFCreateFile(MFFileAccessMode.ReadWrite, MFFileOpenMode.DeleteIfExist, MFFileFlags.None, filename);
                _mediaSink = MFHelper.MFCreateMPEG4MediaSink(_byteStream, _mediaType, null);
    
                // Create sink writer object:
                IMFAttributes attr = null;
                MFHelper.MFCreateAttributes(out attr, 2);
    
                attr.SetGUID(Constants.MF_TRANSCODE_CONTAINERTYPE, Constants.MFTranscodeContainerType_MPEG4);
                attr.SetUINT32(Constants.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 0); // Or 1, doesn't make any difference
    
                _sinkWriter = MFHelper.MFCreateSinkWriterFromMediaSink(_mediaSink, attr);
    
                // Process the input frames:
                ulong _startTime = 0;
    
                _sinkWriter.BeginWriting();
                foreach (byte[] pFrame in pFrames)
                {
                    IMFMediaBuffer mediaBuffer = CreateMediaBuffer(pFrame);
                    IMFSample sample = MFHelper.MFCreateSample();
    
                    sample.AddBuffer(mediaBuffer);
                    sample.SetSampleTime(_startTime);
                    sample.SetSampleDuration(_frameDuration);
    
                    _sinkWriter.WriteSample(0, sample);
    
                    _startTime += _frameDuration;
                }
    
                // Finalize the sink:
                _sinkWriter.DoFinalize(); 
    
                MFHelper.MFShutdown();
            }
    
            private IMFMediaBuffer CreateMediaBuffer(byte[] pFrame)
            {
                IMFMediaBuffer mediaBuffer = MFHelper.MFCreateMemoryBuffer((uint)pFrame.Length);
                IntPtr bufEntry;
                uint maxLength, currentLength;
                mediaBuffer.Lock(out bufEntry, out maxLength, out currentLength);
                System.Runtime.InteropServices.Marshal.Copy(pFrame, 0, bufEntry, pFrame.Length);
                mediaBuffer.Unlock();
                mediaBuffer.SetCurrentLength((uint)pFrame.Length);
    
                return mediaBuffer;
            }
        }


    I pass H.264 frames as binaries as input to the Mux function. As a side note: this code fails when finalizing the sink writer under Windows 7, working on that too.

    Dmitry, could you please share some example code that you use? You could check out the attributes I set in the example code above.

    Thanks!

    *UPDATE: I'll post a link to the generated MP4 once I figure out how to have my account here verified :-/

    *UPDATE 2: link to the generated MP4 file. Contains a H.264 GOP, 1 second long, 10 frames. 

    Friday, July 04, 2014 9:02 AM
  • Alright, I have something that solved the problem. 

    After examining the produced MP4's structure, it turned out that my code generated a "stss" atom with no entries in it. As this atom contains entries regarding key frames in the stream, adding this attribute to the key frame samples 

    sample.SetUINT32(Constants.MFSampleExtension_CleanPoint, (uint)1);

    made the whole thing work as a charm.

    I still have the sink writer crash under Windows 7, but I guess I might have to ask about it in a separate thread..?

    Tuesday, July 15, 2014 2:06 PM