| Index: media/player/view.h
|
| ===================================================================
|
| --- media/player/view.h (revision 0)
|
| +++ media/player/view.h (revision 0)
|
| @@ -0,0 +1,392 @@
|
| +// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
|
| +// source code is governed by a BSD-style license that can be found in the
|
| +// LICENSE file.
|
| +
|
| +// View.h : Paints the current movie frame (with scaling) to the display.
|
| +// TODO(fbarchard): Consider rewriting as view.cc and view.h
|
| +
|
| +#ifndef MEDIA_PLAYER_VIEW_H_
|
| +#define MEDIA_PLAYER_VIEW_H_
|
| +
|
| +// Enable timing code by turning on TESTING macro.
|
| +// #define TESTING 1
|
| +
|
| +#ifdef TESTING
|
| +#define _CRT_SECURE_NO_WARNINGS
|
| +#include <windows.h>
|
| +#include <stdio.h>
|
| +#include <process.h>
|
| +#include <string.h>
|
| +#endif
|
| +
|
| +#include <atlscrl.h>
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "media/base/buffers.h"
|
| +#include "media/base/factory.h"
|
| +#include "media/base/filters.h"
|
| +#include "media/base/yuv_convert.h"
|
| +#include "media/base/yuv_scale.h"
|
| +#include "media/player/wtl_renderer.h"
|
| +
|
| +#include "media/player/movie.h"
|
| +
|
| +#ifdef TESTING
|
| +// Fetch current time as milliseconds.
|
| +// Return as double for high duration and precision.
|
| +static inline double GetTime() {
|
| + LARGE_INTEGER perf_time, perf_hz;
|
| + QueryPerformanceFrequency(&perf_hz); // May change with speed step.
|
| + QueryPerformanceCounter(&perf_time);
|
| + return perf_time.QuadPart * 1000.0 / perf_hz.QuadPart; // Convert to ms.
|
| +}
|
| +#endif
|
| +
|
| +extern bool g_enableswscaler;
|
| +extern bool g_enabledraw;
|
| +extern bool g_enabledump_yuv_file;
|
| +extern int g_view_size;
|
| +
|
| +class WtlVideoWindow : public CScrollWindowImpl<WtlVideoWindow> {
|
| + public:
|
| + DECLARE_WND_CLASS_EX(NULL, 0, -1)
|
| +
|
| + BEGIN_MSG_MAP(WtlVideoWindow)
|
| + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
| + CHAIN_MSG_MAP(CScrollWindowImpl<WtlVideoWindow>);
|
| + END_MSG_MAP()
|
| +
|
| + WtlVideoWindow() {
|
| + size_.cx = 0;
|
| + size_.cy = 0;
|
| + renderer_ = new WtlVideoRenderer(this);
|
| + last_frame_ = NULL;
|
| + }
|
| +
|
| + BOOL PreTranslateMessage(MSG* /*msg*/) {
|
| + return FALSE;
|
| + }
|
| +
|
| + void AllocateVideoBitmap(CDCHandle dc) {
|
| + // See note on SetSize for why we check size_.cy.
|
| + if (bmp_.IsNull() && size_.cy > 0) {
|
| + BITMAPINFO bmi;
|
| + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
| + bmi.bmiHeader.biWidth = size_.cx;
|
| + bmi.bmiHeader.biHeight = size_.cy;
|
| + bmi.bmiHeader.biPlanes = 1;
|
| + bmi.bmiHeader.biBitCount = 32;
|
| + bmi.bmiHeader.biCompression = BI_RGB;
|
| + bmi.bmiHeader.biSizeImage = 0;
|
| + bmi.bmiHeader.biXPelsPerMeter = 100;
|
| + bmi.bmiHeader.biYPelsPerMeter = 100;
|
| + bmi.bmiHeader.biClrUsed = 0;
|
| + bmi.bmiHeader.biClrImportant = 0;
|
| + void* pBits;
|
| + bmp_.CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, &pBits, NULL, 0);
|
| + SetScrollOffset(0, 0, FALSE);
|
| + SetScrollSize(size_);
|
| + }
|
| + }
|
| +
|
| + // Called on the video renderer's thread.
|
| + // Note that AllocateVideoBitmap examines the size_.cy value to determine
|
| + // if a bitmap should be allocated, so we set it last to avoid a race
|
| + // condition.
|
| + void SetSize(int cx, int cy) {
|
| + size_.cx = cx;
|
| + size_.cy = cy;
|
| + }
|
| +
|
| + void Reset() {
|
| + if (!bmp_.IsNull()) {
|
| + bmp_.DeleteObject();
|
| + }
|
| + size_.cx = 0;
|
| + size_.cy = 0;
|
| + // TODO(frank): get rid of renderer at reset too.
|
| + }
|
| +
|
| + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/,
|
| + BOOL& /*bHandled*/) {
|
| + CDCHandle dc = reinterpret_cast<HDC>(wParam);
|
| + AllocateVideoBitmap(dc);
|
| + RECT rect;
|
| + GetClientRect(&rect);
|
| + int x = 0;
|
| + int y = 0;
|
| + if (!bmp_.IsNull()) {
|
| + x = size_.cx + 1;
|
| + y = size_.cy + 1;
|
| + }
|
| + if (rect.right > m_sizeAll.cx) {
|
| + RECT rectRight = rect;
|
| + rectRight.left = x;
|
| + rectRight.bottom = y;
|
| + dc.FillRect(&rectRight, COLOR_WINDOW);
|
| + }
|
| + if (rect.bottom > m_sizeAll.cy) {
|
| + RECT rectBottom = rect;
|
| + rectBottom.top = y;
|
| + dc.FillRect(&rectBottom, COLOR_WINDOW);
|
| + }
|
| + if (!bmp_.IsNull()) {
|
| + dc.MoveTo(size_.cx, 0);
|
| + dc.LineTo(size_.cx, size_.cy);
|
| + dc.LineTo(0, size_.cy);
|
| + }
|
| + return 0;
|
| + }
|
| +
|
| + // Convert the video frame to RGB and Blit.
|
| + void ConvertFrame(media::VideoFrame * video_frame) {
|
| + media::VideoSurface frame_in;
|
| + bool lock_result = video_frame->Lock(&frame_in);
|
| + DCHECK(lock_result);
|
| + BITMAP bm;
|
| + bmp_.GetBitmap(&bm);
|
| + int dibwidth = bm.bmWidth;
|
| + int dibheight = bm.bmHeight;
|
| +
|
| + uint8 *movie_dib_bits = reinterpret_cast<uint8 *>(bm.bmBits) +
|
| + bm.bmWidthBytes * (bm.bmHeight - 1);
|
| + int dibrowbytes = -bm.bmWidthBytes;
|
| + int clipped_width = frame_in.width;
|
| + if (dibwidth < clipped_width) {
|
| + clipped_width = dibwidth;
|
| + }
|
| + int clipped_height = frame_in.height;
|
| + if (dibheight < clipped_height) {
|
| + clipped_height = dibheight;
|
| + }
|
| +
|
| + int scaled_width = clipped_width;
|
| + int scaled_height = clipped_height;
|
| + switch (g_view_size) {
|
| + case 0:
|
| + scaled_width = clipped_width / 2;
|
| + scaled_height = clipped_height / 2;
|
| + break;
|
| +
|
| + case 1:
|
| + default: // Assume 1:1 for stray view sizes
|
| + scaled_width = clipped_width;
|
| + scaled_height = clipped_height;
|
| + break;
|
| +
|
| + case 2:
|
| + scaled_width = clipped_width;
|
| + scaled_height = clipped_height;
|
| + clipped_width = scaled_width / 2;
|
| + clipped_height = scaled_height / 2;
|
| + break;
|
| + }
|
| +
|
| + // Append each frame to end of file.
|
| + if (g_enabledump_yuv_file) {
|
| + DumpYUV(frame_in);
|
| + }
|
| +
|
| +#ifdef TESTING
|
| + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
| + double yuvtimestart = GetTime(); // Start timer.
|
| +#endif
|
| +
|
| + if (g_enabledraw) {
|
| + if (g_enableswscaler) {
|
| + uint8* data_out[3];
|
| + int stride_out[3];
|
| + data_out[0] = movie_dib_bits;
|
| + data_out[1] = NULL;
|
| + data_out[2] = NULL;
|
| + stride_out[0] = dibrowbytes;
|
| + stride_out[1] = 0;
|
| + stride_out[2] = 0;
|
| +
|
| + /*
|
| + if (!sws_context_) {
|
| + DCHECK(frame_in.format == VideoSurface::YV12);
|
| + int outtype = bm.bmBitsPixel == 32 ? PIX_FMT_RGB32 : PIX_FMT_RGB24;
|
| + sws_context_ = sws_getContext(frame_in.width, frame_in.height,
|
| + PIX_FMT_YUV420P, width_, height_,
|
| + outtype, SWS_FAST_BILINEAR,
|
| + NULL, NULL, NULL);
|
| + DCHECK(sws_context_);
|
| + }
|
| +
|
| + sws_scale(sws_context_, frame_in.data, frame_in.strides, 0,
|
| + height_, data_out, stride_out);
|
| + */
|
| + } else {
|
| + DCHECK(bm.bmBitsPixel == 32);
|
| + DrawYUV(frame_in,
|
| + movie_dib_bits,
|
| + dibrowbytes,
|
| + clipped_width,
|
| + clipped_height,
|
| + scaled_width,
|
| + scaled_height);
|
| + }
|
| + }
|
| +#ifdef TESTING
|
| + double yuvtimeend = GetTime(); // Start timer.
|
| + SSetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
| + static int yuvtimecount = 0;
|
| + static double yuvtimesum = 0;
|
| + yuvtimesum += yuvtimeend - yuvtimestart;
|
| + ++yuvtimecount;
|
| +
|
| + char outputbuf[512];
|
| + snprintf(outputbuf, sizeof(outputbuf), "yuv %.2fms avg %.2fms\n",
|
| + yuvtimeend - yuvtimestart, yuvtimesum / yuvtimecount);
|
| + OutputDebugStringA(outputbuf);
|
| +#endif
|
| + }
|
| +
|
| + void DoPaint(CDCHandle dc) {
|
| + AllocateVideoBitmap(dc);
|
| + if (!bmp_.IsNull()) {
|
| + scoped_refptr<media::VideoFrame> frame;
|
| + renderer_->GetCurrentFrame(&frame);
|
| + if (frame.get()) {
|
| + base::TimeDelta frame_timestamp = frame->GetTimestamp();
|
| + if (frame != last_frame_ || frame_timestamp != last_timestamp_) {
|
| + last_frame_ = frame;
|
| + last_timestamp_ = frame_timestamp;
|
| + ConvertFrame(frame);
|
| + }
|
| + frame = NULL;
|
| + }
|
| +
|
| +#ifdef TESTING
|
| + double paint_time_start = GetTime();
|
| + static double paint_time_previous = 0;
|
| + if (!paint_time_previous)
|
| + paint_time_previous = paint_time_start;
|
| +#endif
|
| + CDC dcMem;
|
| + dcMem.CreateCompatibleDC(dc);
|
| + HBITMAP hBmpOld = dcMem.SelectBitmap(bmp_);
|
| + dc.BitBlt(0, 0, size_.cx, size_.cy, dcMem, 0, 0, SRCCOPY);
|
| + dcMem.SelectBitmap(hBmpOld);
|
| +#ifdef TESTING
|
| + double paint_time_end = GetTime();
|
| + static int paint_count = 0;
|
| + static double paint_time_sum = 0;
|
| + paint_time_sum += paint_time_end-paint_time_start;
|
| + ++paint_count;
|
| + char outputbuf[512];
|
| + snprintf(outputbuf, sizeof(outputbuf),
|
| + "paint time %5.2fms blit %5.2fms avg %5.2fms\n",
|
| + paint_time_start-paint_time_previous,
|
| + paint_time_end-paint_time_start,
|
| + paint_time_sum/paint_count);
|
| + OutputDebugStringA(outputbuf);
|
| +
|
| + paint_time_previous = paint_time_start;
|
| +#endif
|
| + }
|
| + } // End of DoPaint function.
|
| +
|
| + CBitmap bmp_; // Used by mainfrm.h.
|
| + SIZE size_; // Used by WtlVideoWindow.
|
| + scoped_refptr<WtlVideoRenderer> renderer_; // Used by WtlVideoWindow.
|
| +
|
| + private:
|
| +
|
| + // Draw a frame of YUV to an RGB buffer with scaling.
|
| + // Handles different YUV formats.
|
| + void DrawYUV(const media::VideoSurface &frame_in,
|
| + uint8 *movie_dib_bits,
|
| + int dibrowbytes,
|
| + int clipped_width,
|
| + int clipped_height,
|
| + int scaled_width,
|
| + int scaled_height) {
|
| + // Normal size
|
| + if (g_view_size == 1) {
|
| + if (frame_in.format == media::VideoSurface::YV16) {
|
| + // Temporary cast, til we use uint8 for VideoFrame.
|
| + media::ConvertYV16ToRGB32((const uint8*)frame_in.data[0],
|
| + (const uint8*)frame_in.data[1],
|
| + (const uint8*)frame_in.data[2],
|
| + movie_dib_bits,
|
| + clipped_width, clipped_height,
|
| + frame_in.strides[0],
|
| + frame_in.strides[1],
|
| + dibrowbytes);
|
| + } else {
|
| + // Temporary cast, til we use uint8 for VideoFrame.
|
| + media::ConvertYV12ToRGB32((const uint8*)frame_in.data[0],
|
| + (const uint8*)frame_in.data[1],
|
| + (const uint8*)frame_in.data[2],
|
| + movie_dib_bits,
|
| + clipped_width, clipped_height,
|
| + frame_in.strides[0],
|
| + frame_in.strides[1],
|
| + dibrowbytes);
|
| + }
|
| + } else {
|
| + if (frame_in.format == media::VideoSurface::YV16) {
|
| + // Temporary cast, til we use uint8 for VideoFrame.
|
| + media::ScaleYV16ToRGB32((const uint8*)frame_in.data[0],
|
| + (const uint8*)frame_in.data[1],
|
| + (const uint8*)frame_in.data[2],
|
| + movie_dib_bits,
|
| + clipped_width, clipped_height,
|
| + scaled_width, scaled_height,
|
| + frame_in.strides[0],
|
| + frame_in.strides[1],
|
| + dibrowbytes);
|
| + } else {
|
| + // Temporary cast, til we use uint8 for VideoFrame.
|
| + media::ScaleYV12ToRGB32((const uint8*)frame_in.data[0],
|
| + (const uint8*)frame_in.data[1],
|
| + (const uint8*)frame_in.data[2],
|
| + movie_dib_bits,
|
| + clipped_width, clipped_height,
|
| + scaled_width, scaled_height,
|
| + frame_in.strides[0],
|
| + frame_in.strides[1],
|
| + dibrowbytes);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Diagnostic function to write out YUV in format compatible with PYUV tool.
|
| + void DumpYUV(const media::VideoSurface &frame_in) {
|
| + FILE * file_yuv = fopen("raw.yuv", "ab+"); // Open for append binary.
|
| + if (file_yuv != NULL) {
|
| + fseek(file_yuv, 0, SEEK_END);
|
| + const size_t frame_size = frame_in.width * frame_in.height;
|
| + for (size_t y = 0; y < frame_in.height; ++y)
|
| + fwrite(frame_in.data[0]+frame_in.strides[0]*y,
|
| + frame_in.width, sizeof(uint8), file_yuv);
|
| + for (size_t y = 0; y < frame_in.height/2; ++y)
|
| + fwrite(frame_in.data[1]+frame_in.strides[1]*y,
|
| + frame_in.width/2, sizeof(uint8), file_yuv);
|
| + for (size_t y = 0; y < frame_in.height/2; ++y)
|
| + fwrite(frame_in.data[2]+frame_in.strides[2]*y,
|
| + frame_in.width/2, sizeof(uint8), file_yuv);
|
| + fclose(file_yuv);
|
| +
|
| +#if TESTING
|
| + static int frame_dump_count = 0;
|
| + char outputbuf[512];
|
| + snprintf(outputbuf, sizeof(outputbuf), "yuvdump %4d %dx%d stride %d\n",
|
| + frame_dump_count, frame_in.width, frame_in.height,
|
| + frame_in.strides[0]);
|
| + OutputDebugStringA(outputbuf);
|
| + ++frame_dump_count;
|
| +#endif
|
| + }
|
| + }
|
| +
|
| + media::VideoFrame* last_frame_;
|
| + base::TimeDelta last_timestamp_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(WtlVideoWindow);
|
| +};
|
| +
|
| +#endif // MEDIA_PLAYER_VIEW_H_
|
| +
|
|
|