123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- #include "main.h"
- #include "vid_subs.h"
- #include "vid_gdi+.h"
- #include "WinampAttributes.h"
- #include "../nu/AutoWide.h"
- #include "../nsutil/image.h"
- GDIPVideoOutput gdiplusVideo;
- static void colorspace_convert(UINT inputtype, const char * inputbuf, char * output, int flip, int width, int height);
- void GDIPVideoOutput::SetupGraphics()
- {
- // create new canvas
- if (graphics) delete graphics;
- graphics = new Graphics(parent, FALSE);
- graphics->Clear(Color(0));
- HDC h = graphics->GetHDC();
- // recreate back device context
- if (graphicsback) delete graphicsback; // we must delete this before deleting backdc
- if (backdc) DeleteDC(backdc);
- backdc = CreateCompatibleDC(h);
- // make sure back device context has right size and color depth
- HBITMAP memBM = CreateCompatibleBitmap(h, winw, winh);
- SelectObject(backdc, memBM);
- DeleteObject(memBM);
- // create back graphics canvas
- graphicsback = new Graphics(backdc);
- graphicsback->Clear(Color(0));
- graphics->ReleaseHDC(h);
- // set parameters
- /* fuck it, all default for now.
- graphicsback->SetInterpolationMode(InterpolationModeBilinear);
- graphicsback->SetCompositingQuality(CompositingQualityHighSpeed);
- graphicsback->SetCompositingMode(CompositingModeSourceCopy);
- graphicsback->SetSmoothingMode(SmoothingModeNone);
- */
- }
- GDIPVideoOutput::GDIPVideoOutput() : graphics(0), frame(0), type(0), graphicsback(0), backdc(0), w(0), h(0), flip(0), winw(0), winh(0), gdiplusToken(0), subs(0), needschange(0), parent(0), adjuster(0)
- {
- }
- GDIPVideoOutput::~GDIPVideoOutput()
- {
- }
- int GDIPVideoOutput::create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int type, int flipit, double aspectratio) //return 1 if ok
- {
- GdiplusStartupInput gdiplusStartupInput;
- GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
- needschange = 1;
- adjuster = _adjuster;
- needschange = 0;
- RECT r;
- GetWindowRect(parent, &r);
- winw = r.right - r.left;
- winh = r.bottom = r.top;
- this->parent = parent;
- this->flip = flipit;
- this->w = w;
- this->h = h;
- this->type = type;
- SetupGraphics();
- frame = new Bitmap(w, h, graphicsback);
- ZeroMemory(&lastrect, sizeof(RECT));
- return 1;
- }
- // TODO: verify that this works
- bool GDIPVideoOutput::FillFrame(Bitmap * frame, void *buf)
- {
- switch (type)
- {
- case VIDEO_MAKETYPE('R', 'G', '3', '2'):
- {
- BITMAPINFO info;
- info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- info.bmiHeader.biWidth = w;
- info.bmiHeader.biHeight = h;
- info.bmiHeader.biPlanes = 1;
- info.bmiHeader.biBitCount = 32;
- info.bmiHeader.biCompression = BI_RGB;
- info.bmiHeader.biSizeImage = 0;
- info.bmiHeader.biXPelsPerMeter = 0;
- info.bmiHeader.biYPelsPerMeter = 0;
- info.bmiHeader.biXPelsPerMeter = 0;
- info.bmiHeader.biYPelsPerMeter = 0;
- info.bmiHeader.biClrUsed = 0;
- info.bmiHeader.biClrImportant = 0;
- frame->FromBITMAPINFO(&info, buf);
- }
- return true;
- case VIDEO_MAKETYPE('R', 'G', '2', '4'):
- {
- BITMAPINFO info;
- info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- info.bmiHeader.biWidth = w;
- info.bmiHeader.biHeight = h;
- info.bmiHeader.biPlanes = 1;
- info.bmiHeader.biBitCount = 24;
- info.bmiHeader.biCompression = BI_RGB;
- info.bmiHeader.biSizeImage = 0;
- info.bmiHeader.biXPelsPerMeter = 0;
- info.bmiHeader.biYPelsPerMeter = 0;
- info.bmiHeader.biXPelsPerMeter = 0;
- info.bmiHeader.biYPelsPerMeter = 0;
- info.bmiHeader.biClrUsed = 0;
- info.bmiHeader.biClrImportant = 0;
- frame->FromBITMAPINFO(&info, buf);
- }
- return true;
- }
- return false;
- }
- void GDIPVideoOutput::displayFrame(const char *buf, int size, int time)
- {
- // TODO: verify that this works before uncommenting if (!FillFrame(frame, const_cast<char *>(buf)))
- {
- BitmapData d;
- d.Width = w;
- d.Height = h;
- d.PixelFormat = PixelFormat32bppRGB;
- d.Stride = 4 * w;
- d.Scan0 = 0;
- // write the frame to our bitmap object
- if (frame->LockBits(&Rect(0, 0, w, h), ImageLockModeWrite, PixelFormat32bppRGB, &d) != Ok)
- {
- needschange = 1; return;
- }
- colorspace_convert(type, buf, (char*)d.Scan0, flip, w, h);
- frame->UnlockBits(&d);
- }
- // fix aspect ratio
- RECT r = {0, 0, winw, winh};
- adjuster->adjustAspect(r);
- if (memcmp(&r, &lastrect, sizeof(RECT))) graphicsback->Clear(Color(0));
- lastrect = r;
- // draw the image
- graphicsback->DrawImage(frame, r.left, r.top, r.right - r.left, r.bottom - r.top);
- if (subs)
- { // draw subtitles
- //graphicsback->DrawString(AutoWide(subs->text),-1,&Font(L"Arial.ttf",36),PointF(subs->xPos,subs->yPos),&SolidBrush(Color(subs->colorRed,subs->colorGreen,subs->colorBlue)));
- }
- // flip graphics and graphicsback
- HDC h = graphics->GetHDC();
- HDC b = graphicsback->GetHDC();
- BitBlt(h, r.left, r.top, r.right - r.left, r.bottom - r.top, b, r.left, r.top, SRCCOPY);
- graphicsback->ReleaseHDC(b);
- graphics->ReleaseHDC(h);
- }
- int GDIPVideoOutput::needChange()
- {
- return needschange;
- }
- void GDIPVideoOutput::close()
- {
- if (graphics) delete graphics; graphics = 0;
- if (frame) delete frame; frame = 0;
- if (graphicsback) delete graphicsback; graphicsback = 0;
- if (backdc) DeleteDC(backdc); backdc = 0;
- subs = 0;
- type = 0;
- GdiplusShutdown(gdiplusToken);
- }
- void GDIPVideoOutput::Refresh()
- {}
- void GDIPVideoOutput::timerCallback()
- {
- RECT r;
- GetWindowRect(parent, &r);
- UINT w, h;
- w = r.right - r.left;
- h = r.bottom - r.top;
- bool change = (w != winw || h != winh);
- if (change)
- {
- winw = w;
- winh = h;
- // sizes have changed, we must reset the graphics
- SetupGraphics();
- }
- }
- //mmm. ctrl+c ctrl+v.
- static void colorspace_convert(UINT type, const char * buf, char * lpSurface, int flip, int width, int height)
- {
- const int lPitch = width * 4;
- if (type == VIDEO_MAKETYPE('Y', 'V', '1', '2'))
- {
- const YV12_PLANES *planes = (YV12_PLANES *)buf;
- // convert yv12 to rgb
- const int bytes = 4;
- int i, j, y00, y01, y10, y11, u, v;
- unsigned char *pY = (unsigned char *)planes->y.baseAddr;
- unsigned char *pU = (unsigned char *)planes->u.baseAddr;
- unsigned char *pV = (unsigned char *)planes->v.baseAddr;
- unsigned char *pOut = (unsigned char*)lpSurface;
- const int rvScale = (int)(2.017 * 65536.0); //91881;
- const int gvScale = - (int)(0.392 * 65536.0); // -22553;
- const int guScale = - (int)(0.813 * 65536.0); // -46801;
- const int buScale = (int)(1.596 * 65536.0); //116129;
- const int yScale = (int)(1.164 * 65536.0); //(1.164*65536.0);
- int addOut = lPitch * 2 - width * bytes;
- int yrb = planes->y.rowBytes;
- int addL = lPitch;
- /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
- #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
- if (flip)
- {
- pOut += (lPitch) * (height - 1);
- addOut = -lPitch * 2 - width * bytes;
- addL = -addL;
- }
- for (j = 0; j <= height - 2; j += 2)
- {
- for (i = 0; i <= width - 2; i += 2)
- {
- y00 = *pY - 16;
- y01 = *(pY + 1) - 16;
- y10 = *(pY + yrb) - 16;
- y11 = *(pY + yrb + 1) - 16;
- u = (*pU++) - 128;
- v = (*pV++) - 128;
- {
- int r, g, b;
- g = guScale * v + gvScale * u;
- r = buScale * v;
- b = rvScale * u;
- y00 *= yScale; y01 *= yScale;
- y10 *= yScale; y11 *= yScale;
- {
- {
- unsigned char *rgb = pOut;
- /* Write out top two pixels */
- rgb[0] = LIMIT(b + y00); rgb[1] = LIMIT(g + y00); rgb[2] = LIMIT(r + y00);
- rgb[4] = LIMIT(b + y01); rgb[5] = LIMIT(g + y01); rgb[6] = LIMIT(r + y01);
- /* Skip down to next line to write out bottom two pixels */
- rgb += addL;
- rgb[0] = LIMIT(b + y10); rgb[1] = LIMIT(g + y10); rgb[2] = LIMIT(r + y10);
- rgb[4] = LIMIT(b + y11); rgb[5] = LIMIT(g + y11); rgb[6] = LIMIT(r + y11);
- }
- }
- }
- pY += 2;
- pOut += 2 * bytes;
- }
- pY += yrb + yrb - width;
- pU += planes->u.rowBytes - width / 2;
- pV += planes->v.rowBytes - width / 2;
- pOut += addOut;
- }
- }
- else if (type == VIDEO_MAKETYPE('R', 'G', '3', '2'))
- {
- if (flip)
- nsutil_image_CopyFlipped_U8((uint8_t *)lpSurface, lPitch, (const uint8_t *)buf, width*4, width, height);
- else
- nsutil_image_Copy_U8((uint8_t *)lpSurface, lPitch, (const uint8_t *)buf, width*4, width, height);
- }
- else if (type == VIDEO_MAKETYPE('Y', 'U', 'Y', '2') || type == VIDEO_MAKETYPE('U', 'Y', 'V', 'Y'))
- {
- char *b = (char *)lpSurface;
- int l2 = lPitch;
- if (flip)
- {
- b += (height - 1) * l2;
- l2 = -l2;
- }
- {
- {
- // yuy2->rgb32 conversion
- unsigned char *src = (unsigned char *)buf;
- unsigned char *dst = (unsigned char *)lpSurface;
- int line, col; //, linewidth;
- int y, yy;
- int u, v;
- int vr, ug, vg, ub;
- unsigned char *py, *pu, *pv;
- //linewidth = width - (width >> 1);
- py = src;
- pu = src + 1;
- pv = src + 3;
- int pitchadd = lPitch - (width * 4);
- for (line = 0; line < height; line++)
- {
- for (col = 0; col < width; col++)
- {
- #undef LIMIT
- #define LIMIT(x) ( (x) > 0xffff ? 0xff : ( (x) <= 0xff ? 0 : ( (x) >> 8 ) ) )
- y = *py;
- yy = y << 8;
- u = *pu - 128;
- ug = 88 * u;
- ub = 454 * u;
- v = *pv - 128;
- vg = 183 * v;
- vr = 359 * v;
- *dst++ = LIMIT(yy + ub); // b
- *dst++ = LIMIT(yy - ug - vg); // g
- *dst++ = LIMIT(yy + vr); // r
- dst++;
- py += 2;
- if ((col & 1) == 1)
- {
- pu += 4; // skip yvy every second y
- pv += 4; // skip yuy every second y
- }
- } // ..for col
- dst += pitchadd;
- } /* ..for line */
- }
- }
- }
- else if (type == VIDEO_MAKETYPE('R', 'G', '2', '4'))
- {
- if (flip)
- nsutil_image_ConvertFlipped_RGB24_RGB32((RGB32 *)lpSurface, lPitch, (const uint8_t *)buf, width*3, width, height);
- else
- nsutil_image_Convert_RGB24_RGB32((RGB32 *)lpSurface, lPitch, (const uint8_t *)buf, width*3, width, height);
-
- }
- }
|