Second attempt at removing executable bits from media/mf files
[chromium-blink-merge.git] / media / mf / basic_renderer.cc
blobb85afd5e36783fd05e51c88cc6b8560cd1a0b6b7
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mf/basic_renderer.h"
7 #include <d3d9.h>
8 #include <mfapi.h>
9 #include <mfidl.h>
11 #include "base/message_loop.h"
12 #include "base/scoped_comptr_win.h"
13 #include "base/time.h"
14 #include "media/base/yuv_convert.h"
16 // For MFGetService and MF_BUFFER_SERVICE (getting D3D surface from buffer)
17 #pragma comment(lib, "mf.lib")
18 #pragma comment(lib, "strmiids.lib")
20 namespace media {
22 // Converts the given raw data buffer into RGB32 format, and drawing the result
23 // into the given window. This is only used when DXVA2 is not enabled.
24 // Returns: true on success.
25 bool ConvertToRGBAndDrawToWindow(HWND video_window, uint8* data, int width,
26 int height, int stride) {
27 CHECK(video_window != NULL);
28 CHECK(data != NULL);
29 CHECK_GT(width, 0);
30 CHECK_GT(height, 0);
31 CHECK_GE(stride, width);
32 height = (height + 15) & ~15;
33 bool success = true;
34 uint8* y_start = reinterpret_cast<uint8*>(data);
35 uint8* u_start = y_start + height * stride * 5 / 4;
36 uint8* v_start = y_start + height * stride;
37 static uint8* rgb_frame = new uint8[height * stride * 4];
38 int y_stride = stride;
39 int uv_stride = stride / 2;
40 int rgb_stride = stride * 4;
41 ConvertYUVToRGB32(y_start, u_start, v_start, rgb_frame,
42 width, height, y_stride, uv_stride,
43 rgb_stride, YV12);
44 PAINTSTRUCT ps;
45 InvalidateRect(video_window, NULL, TRUE);
46 HDC hdc = BeginPaint(video_window, &ps);
47 BITMAPINFOHEADER hdr;
48 hdr.biSize = sizeof(BITMAPINFOHEADER);
49 hdr.biWidth = width;
50 hdr.biHeight = -height; // minus means top-down bitmap
51 hdr.biPlanes = 1;
52 hdr.biBitCount = 32;
53 hdr.biCompression = BI_RGB; // no compression
54 hdr.biSizeImage = 0;
55 hdr.biXPelsPerMeter = 1;
56 hdr.biYPelsPerMeter = 1;
57 hdr.biClrUsed = 0;
58 hdr.biClrImportant = 0;
59 int rv = StretchDIBits(hdc, 0, 0, width, height, 0, 0, width, height,
60 rgb_frame, reinterpret_cast<BITMAPINFO*>(&hdr),
61 DIB_RGB_COLORS, SRCCOPY);
62 if (rv == 0) {
63 LOG(ERROR) << "StretchDIBits failed";
64 MessageLoopForUI::current()->QuitNow();
65 success = false;
67 EndPaint(video_window, &ps);
69 return success;
72 // Obtains the underlying raw data buffer for the given IMFMediaBuffer, and
73 // calls ConvertToRGBAndDrawToWindow() with it.
74 // Returns: true on success.
75 bool PaintMediaBufferOntoWindow(HWND video_window, IMFMediaBuffer* video_buffer,
76 int width, int height, int stride) {
77 CHECK(video_buffer != NULL);
78 HRESULT hr;
79 BYTE* data;
80 DWORD buffer_length;
81 DWORD data_length;
82 hr = video_buffer->Lock(&data, &buffer_length, &data_length);
83 if (FAILED(hr)) {
84 LOG(ERROR) << "Failed to lock IMFMediaBuffer";
85 return false;
87 if (!ConvertToRGBAndDrawToWindow(video_window,
88 reinterpret_cast<uint8*>(data),
89 width,
90 height,
91 stride)) {
92 LOG(ERROR) << "Failed to convert raw buffer to RGB and draw to window";
93 video_buffer->Unlock();
94 return false;
96 video_buffer->Unlock();
97 return true;
100 // Obtains the D3D9 surface from the given IMFMediaBuffer, then calls methods
101 // in the D3D device to draw to the window associated with it.
102 // Returns: true on success.
103 bool PaintD3D9BufferOntoWindow(IDirect3DDevice9* device,
104 IMFMediaBuffer* video_buffer) {
105 CHECK(device != NULL);
106 ScopedComPtr<IDirect3DSurface9> surface;
107 HRESULT hr = MFGetService(video_buffer, MR_BUFFER_SERVICE,
108 IID_PPV_ARGS(surface.Receive()));
109 if (FAILED(hr)) {
110 LOG(ERROR) << "Failed to get D3D9 surface from buffer";
111 return false;
113 hr = device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0),
114 1.0f, 0);
115 if (FAILED(hr)) {
116 LOG(ERROR) << "Device->Clear() failed";
117 return false;
119 ScopedComPtr<IDirect3DSurface9> backbuffer;
120 hr = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO,
121 backbuffer.Receive());
122 if (FAILED(hr)) {
123 LOG(ERROR) << "Device->GetBackBuffer() failed";
124 return false;
126 hr = device->StretchRect(surface.get(), NULL, backbuffer.get(), NULL,
127 D3DTEXF_NONE);
128 if (FAILED(hr)) {
129 LOG(ERROR) << "Device->StretchRect() failed";
130 return false;
132 hr = device->Present(NULL, NULL, NULL, NULL);
133 if (FAILED(hr)) {
134 if (hr == E_FAIL) {
135 LOG(WARNING) << "Present() returned E_FAIL";
136 } else {
137 static int frames_dropped = 0;
138 LOG(ERROR) << "Device->Present() failed "
139 << std::hex << std::showbase << hr;
140 if (++frames_dropped == 10) {
141 LOG(ERROR) << "Dropped too many frames, quitting";
142 MessageLoopForUI::current()->QuitNow();
143 return false;
147 return true;
150 static void ReleaseOutputBuffer(VideoFrame* frame) {
151 if (frame != NULL &&
152 frame->type() == VideoFrame::TYPE_MFBUFFER ||
153 frame->type() == VideoFrame::TYPE_DIRECT3DSURFACE) {
154 static_cast<IMFMediaBuffer*>(frame->private_buffer())->Release();
158 // NullRenderer
160 NullRenderer::NullRenderer(MftH264Decoder* decoder) : MftRenderer(decoder) {}
161 NullRenderer::~NullRenderer() {}
163 void NullRenderer::ProcessFrame(scoped_refptr<VideoFrame> frame) {
164 ReleaseOutputBuffer(frame);
165 MessageLoop::current()->PostTask(
166 FROM_HERE, NewRunnableMethod(decoder_.get(),
167 &MftH264Decoder::GetOutput));
170 void NullRenderer::StartPlayback() {
171 MessageLoop::current()->PostTask(
172 FROM_HERE, NewRunnableMethod(decoder_.get(),
173 &MftH264Decoder::GetOutput));
176 void NullRenderer::StopPlayback() {
177 MessageLoop::current()->Quit();
180 // BasicRenderer
182 BasicRenderer::BasicRenderer(MftH264Decoder* decoder,
183 HWND window, IDirect3DDevice9* device)
184 : MftRenderer(decoder),
185 window_(window),
186 device_(device) {
189 BasicRenderer::~BasicRenderer() {}
191 void BasicRenderer::ProcessFrame(scoped_refptr<VideoFrame> frame) {
192 if (device_ != NULL) {
193 if (!PaintD3D9BufferOntoWindow(device_,
194 static_cast<IMFMediaBuffer*>(frame->private_buffer()))) {
195 MessageLoopForUI::current()->QuitNow();
197 } else {
198 if (!PaintMediaBufferOntoWindow(
199 window_, static_cast<IMFMediaBuffer*>(frame->private_buffer()),
200 frame->width(), frame->height(), frame->stride(0))) {
201 MessageLoopForUI::current()->QuitNow();
204 ReleaseOutputBuffer(frame);
205 MessageLoopForUI::current()->PostDelayedTask(
206 FROM_HERE, NewRunnableMethod(decoder_.get(),
207 &MftH264Decoder::GetOutput),
208 frame->GetDuration().InMilliseconds());
211 void BasicRenderer::StartPlayback() {
212 MessageLoopForUI::current()->PostTask(
213 FROM_HERE, NewRunnableMethod(decoder_.get(),
214 &MftH264Decoder::GetOutput));
217 void BasicRenderer::StopPlayback() {
218 MessageLoopForUI::current()->Quit();
221 } // namespace media