1

I was learning to create video files with raw fixed colored images using Windows Media Foundation using this tutorial http://blogs.msdn.com/b/eternalcoding/archive/2013/03/06/developing-a-winrt-component-to-create-a-video-file-using-media-foundation.aspx

I was able to create RGB encoded WMV video shown in the above link. But i need to create YUV encoded MP4 video in NV12 format from image. Since NV12 use (W x H x 3/2) bytes of memory buffer for each frame, i created (W x H x 3/2) bytes of buffer for image buffer(variable 'target' in the tutorial) and set some fixed values to it as image data. Then set image stride 'W' (ARGB uses Wx4 as stride) for the MFCopyImage() and height is set to just 'H'. But that doesn't seem to work. MF_MT_SUBTYPE is set to MFVideoFormat_NV12.

What is the correct way to create a NV12 encoded mp4 video file?

croc
  • 241
  • 1
  • 4
  • 13

1 Answers1

1

I suspect you are doing too much of the work (which hopefully is good news). First keep in mind that the example does not encode the output as RGB. RGB was simply the input type to the sink, and you can feel free to leave it that way.

The container is MFTranscodeContainerType_ASF (more on that in a sec), and the subtypte is MFVideoFormat_WMV3, and the result is a well compressed windows media video file.

When the sink writer is created, in your case the container is automatically created, since the attribute wasn't specified. In fact, the only attribute added is MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS on the following lines:

MFCreateAttributes(&spAttr, 10);
spAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true);
hr = MFCreateSinkWriterFromURL(L".wmv", 
                               spByteStream.Get(), 
                               spAttr.Get(), 
                               &sinkWriter);

Which begs the question - 'why are 10 attributes allocated?' ... (shrug) oh well, doesn't matter.

The point being, you send RGB frames to the sink, and transforms are being done to complete the encoding to your specification. Containers may be found here:

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

and prior to creating the sink, you would specify a given container similar to the following:

spAttr->SetGUID(MF_TRANSCODE_CONTAINERTYPE, MFTranscodeContainerType_ASF);
// or MFTranscodeContainerType_MPEG4, MFTranscodeContainerType_AVI, etc

You previously set the subtype using the following line:

hr = mediaTypeOut->SetGUID(MF_MT_SUBTYPE, encodingFormat);
// where encodingFormat was hardcoded to MFVideoFormat_WMV3 in the ctor

Keep in mind however, some formats expect bottom-up images. Try changing the file extension to ".mp4", container to MFTranscodeContainerType_AVI, and the subtype to MFVideoFormat_NV12 and you will see your same video upside-down. And your file will be huge comparing to the wmv since all of the YUV values are placed into the file.

Getting the container and format details correct requires a good deal of care, and some details are difficult to research.

Hope this helps.

Jeff
  • 2,495
  • 18
  • 38
  • Thanks lot. I really appreciate your detailed explanation and it is really helpful for a novice like me. I also came across this http://msdn.microsoft.com/en-us/library/windows/desktop/ff819477%28v=vs.85%29.aspx From what i understand that this code uses sink writer to write into file 'output.wmv'. But the code gets an accessviolation exception at 'MFCreateSinkWriterFromURL(L"output.wmv", NULL, NULL, &pSinkWriter);' in 'InitializeSinkWriter()'. I would like to ask you, Can you identify what might be the problem? – croc Sep 27 '14 at 14:18
  • Hello. I have run into a little problem. I was writing the code today to include MF_TRANSCODE_CONTAINERTYPE. But it says MF_TRANSCODE_CONTAINERTYPE is undefined. I have included 'Mfidl.h' but still i cannot seem to find the appropriate header file. – croc Sep 29 '14 at 04:13
  • @croc - weird. Check the order, and where each header file is included. It is easiest if you are using precompiled header (as you may already know). – Jeff Sep 29 '14 at 15:00
  • I looked through the Mfidl.h file. The portion with MF_TRANSCODE_CONTAINERTYPE was grayed out. So copied that portion into my solution file and code worked ok. I am defining input as MFVideoFormat_RGB32 and output as MFVideoFormat_NV12 and container type as MFTranscodeContainerType_AVI. Instead of sending NV12 formatted frame i am sending ARGB frames and an mp4 file is created without any error. Is there any way for me to check if the output video frame format is really NV12 encoded? And If i change container from AVI to MPGE4 no video is produced. – croc Sep 30 '14 at 11:26
  • 1
    First, there is a reason why it is grayed out. You should determine what preprocessor directive (in Mfidl.h) is evaluated to gray it out. To verify the type of video stream, use a utility such as 'MediaInfo' (there may be better utilities). If you use MediaInfo, there are several views to choose from which show various info. Lastly, getting the container / subtype settings correct can be difficult, and hard to research. Good luck with your project. – Jeff Sep 30 '14 at 14:26