Showing results for 
Search instead for 
Did you mean: 

BMP to YUV420 to H264 encode problem with odd-sized images

I am trying to convert some .bmp into h264 to be streamed. Basically a bitmap bytestream is sent over to be encoded.
I looked thru the samples/forum and got enough ideas to get started and so far I got some pretty good results.
The only problem I have right now is bitmaps with non-even width/height is not encoded correctly - in VLC it's just a green screen. With even-numbered width/height images the h264 file is correct.
I tried passing-in the stride of the bitmap (via C# BitmapData.Stride) but still getting the green image.
The C/IPP dll:
[cpp]void ConvertBGRtoYUV420(Ipp8u* rgbData, Ipp8u* yuvData, int imgWidth, int imgHeight, int stride, int frameNumber) { Ipp8u* yuv[3]; int yuvStep[3] = {imgWidth, imgWidth/2, imgWidth/2}; int srcStep = stride; IppiSize srcSize = {imgWidth, imgHeight}; for(int i = 0; i < frameNumber; ++i) { yuv[0] = yuvData + i * imgWidth * imgHeight * 3/2; yuv[1] = yuv[0] + imgWidth * imgHeight; yuv[2] = yuv[1] + imgWidth * imgHeight / 4; ippiBGRToYCbCr420_8u_C3P3R(rgbData, srcStep, yuv, yuvStep, srcSize); } } // bmp is in BGR, not RGB! int EncodeStream(Ipp8u* inData, int imgWidth, int imgHeight, int frameNumber, Ipp8u* encodedData, int& VideoDataSize, int stride) { Ipp8u *cYUVData = ippsMalloc_8u(200000000); ConvertBGRtoYUV420(inData, cYUVData, imgWidth, imgHeight, stride, frameNumber); UMC::Status status; UMC::MediaData DataOut; UMC::VideoData DataIn; int FrameSize; UMC::H264EncoderParams Params; UMC::H264VideoEncoder H264Encoder; //Params.key_frame_controls.method=1; Params.B_frame_rate = 0; Params.key_interval = 1; = imgHeight; = imgWidth; = 1000000; Params.numThreads = 1; // roi = entire img IppiSize roi; roi.width = imgWidth; roi.height = imgHeight; if((status = H264Encoder.Init(&Params))!=UMC::UMC_OK) return -1; FrameSize = imgWidth * imgHeight * 3/2; DataIn.Init(imgWidth,imgHeight,UMC::YUV420,8); DataIn.SetBufferPointer(inData,FrameSize); DataIn.SetDataSize(FrameSize); DataOut.SetBufferPointer(encodedData, 100000000); VideoDataSize=0; int nEncodedFrames=0; while ( nEncodedFrames < frameNumber) { status = H264Encoder.GetFrame(&DataIn, &DataOut); if (status == UMC::UMC_OK) { nEncodedFrames++; VideoDataSize+=DataOut.GetDataSize(); DataOut.MoveDataPointer(DataOut.GetDataSize()); cYUVData += FrameSize; DataIn.SetBufferPointer(cYUVData,FrameSize); DataIn.SetDataSize(FrameSize); } } return TRUE; }[/cpp]
The call from C#:
[bash]Image img = new Bitmap(@"C:\test.bmp"); const string fileName = @"C:\output.h264"; BinaryWriter bw = new BinaryWriter(File.Open(fileName, FileMode.Create)); byte[] data; byte[] output; var bmd = (img as Bitmap).LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); // first row of pixels IntPtr ptr = bmd.Scan0; int bytes = Math.Abs(bmd.Stride)*img.Height; data = new byte[bytes]; // copy rgb values into array Marshal.Copy(ptr, data, 0, bytes); output = new byte[bytes]; int size = 0; int ret = ConvertBGRtoYUV420(data, img.Width, img.Height, 100, output, ref size, bmd.Stride); bw.Write(output); bw.Close();[/bash][bash]Any ideas on what I'm doing wrong in handling non-even width/height bitmaps?[/bash]
0 Kudos
2 Replies
Valued Contributor I

If I am not mistaken, width and height not divisible by 2 are not supported in H.264. The only thing you can do is crop or upscale.


I see. Thanks for the insight.