Intel® Integrated Performance Primitives
Deliberate problems developing high-performance vision, signal, security, and storage applications.
Announcements
FPGA community forums and blogs have moved to the Altera Community. Existing Intel Community members can sign in with their current credentials.
6818 Discussions

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

cks2k2
Beginner
1,897 Views
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; Params.info.clip_info.height = imgHeight; Params.info.clip_info.width = imgWidth; Params.info.bitrate = 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
levicki
Valued Contributor I
1,897 Views
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.

0 Kudos
cks2k2
Beginner
1,897 Views
I see. Thanks for the insight.
0 Kudos
Reply