mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-18 20:35:46 -04:00
Initial community commit
This commit is contained in:
21
Src/nsv/nsvplay/IDataReader.h
Normal file
21
Src/nsv/nsvplay/IDataReader.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef NULLSOFT_NSV_NSVPLAY_IDATAREADER_H
|
||||
#define NULLSOFT_NSV_NSVPLAY_IDATAREADER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
class IDataReader
|
||||
{
|
||||
public:
|
||||
virtual ~IDataReader() { }
|
||||
virtual size_t read(char *buf, size_t len)=0; // returns bytes read
|
||||
virtual bool iseof()=0;
|
||||
virtual char *geterror()=0;
|
||||
virtual char *gettitle() { return 0; }
|
||||
virtual char *getheader(char *header_name) { return 0; }
|
||||
virtual bool canseek() { return 0; }
|
||||
virtual int seek(uint64_t newpos) { return 1; }
|
||||
virtual uint64_t getsize() { return ~0; }
|
||||
};
|
||||
|
||||
#endif
|
661
Src/nsv/nsvplay/about.h
Normal file
661
Src/nsv/nsvplay/about.h
Normal file
@ -0,0 +1,661 @@
|
||||
#ifndef _ABOUT_H_
|
||||
#define _ABOUT_H_
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
#pragma warning(disable : 4731)
|
||||
|
||||
static HWND about_hwnd;
|
||||
|
||||
#ifndef NO_ABOUT_EGG
|
||||
|
||||
#define BITMAP_W 100
|
||||
#define BITMAP_H 64
|
||||
static HDC m_hdc;
|
||||
static HBITMAP m_hbm;
|
||||
static char *m_dib;
|
||||
static char ge_fbuf[(BITMAP_H+1)*BITMAP_W+1];
|
||||
static int ge_tmp;
|
||||
#define M_NUM_FX 9
|
||||
static int m_effect;
|
||||
#define BLOBS_NPOINTS 8
|
||||
static int BLOBPOINTS[4*BLOBS_NPOINTS];
|
||||
static int fire_textcnt,fire_textpos;
|
||||
static char *fire_texts[]={
|
||||
"nsvplay",
|
||||
"Nullsoft 2003-8",
|
||||
"",
|
||||
"greets to",
|
||||
"winamp forums",
|
||||
"#nullsoft",
|
||||
"britney spears",
|
||||
"p.s.",
|
||||
"DrO was here",
|
||||
" <3",
|
||||
"",
|
||||
};
|
||||
static HDC scrolldc;
|
||||
static HBITMAP scrollbitmap;
|
||||
static char *scrolldib;
|
||||
static const char scrolltext[]="nullsoft presents you nSVpLAY hidden part! cracked by rOn +5 trainer by deadbeef ";
|
||||
static int scrolloffs;
|
||||
static char *rototmp;
|
||||
|
||||
#endif //NO_ABOUT_EGG
|
||||
|
||||
static INT_PTR CALLBACK aboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
#ifndef NO_ABOUT_EGG
|
||||
{
|
||||
HBITMAP about_bmp = NULL;
|
||||
m_effect=M_NUM_FX-1;
|
||||
|
||||
// try to use the localised image and then revert to the normal dll image
|
||||
about_bmp = (HBITMAP)LoadImage((HINSTANCE)lParam,MAKEINTRESOURCE(IDB_BITMAP1),IMAGE_BITMAP,0,0,LR_SHARED);
|
||||
if(about_bmp == NULL){
|
||||
about_bmp = (HBITMAP)LoadImage(g_hInstance,MAKEINTRESOURCE(IDB_BITMAP1),IMAGE_BITMAP,0,0,LR_SHARED);
|
||||
}
|
||||
|
||||
// set on control with id of -1 (0xFFFFFFFF) or 0xFFFF (not sure how/why this happened)
|
||||
SendDlgItemMessage(hwndDlg,0xFFFF,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)about_bmp);
|
||||
SendDlgItemMessage(hwndDlg,-1,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)about_bmp);
|
||||
}
|
||||
#endif
|
||||
SetDlgItemText(hwndDlg,IDC_VERSION,WNDMENU_CAPTION);
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDCANCEL:
|
||||
case IDOK:
|
||||
#ifndef MODAL_ABOUT
|
||||
DestroyWindow(hwndDlg);
|
||||
#else
|
||||
EndDialog(hwndDlg,1);
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
about_hwnd=NULL;
|
||||
#ifndef NO_ABOUT_EGG
|
||||
if (m_hbm) DeleteObject(m_hbm);
|
||||
if (m_hdc) DeleteDC(m_hdc);
|
||||
if (scrollbitmap) DeleteObject(scrollbitmap);
|
||||
if (scrolldc) DeleteDC(scrolldc);
|
||||
m_hbm=0;
|
||||
m_hdc=0;
|
||||
scrollbitmap=0;
|
||||
scrolldc=0;
|
||||
if (rototmp) free(rototmp);
|
||||
rototmp=NULL;
|
||||
#endif
|
||||
break;
|
||||
#ifndef NO_ABOUT_EGG
|
||||
case WM_LBUTTONDBLCLK :
|
||||
//easter eggs :)
|
||||
if (++m_effect >= M_NUM_FX) m_effect=1;
|
||||
|
||||
KillTimer(hwndDlg,0x1234);
|
||||
|
||||
if (m_hbm) DeleteObject(m_hbm);
|
||||
if (m_hdc) DeleteDC(m_hdc);
|
||||
if (scrollbitmap) DeleteObject(scrollbitmap);
|
||||
if (scrolldc) DeleteDC(scrolldc);
|
||||
scrollbitmap=0;
|
||||
scrolldc=0;
|
||||
if (rototmp) free(rototmp);
|
||||
rototmp=NULL;
|
||||
|
||||
{
|
||||
struct
|
||||
{
|
||||
BITMAPINFO bmi;
|
||||
RGBQUAD more_bmiColors[256];
|
||||
LPVOID data;
|
||||
} m_bitmap;
|
||||
m_hdc = CreateCompatibleDC(NULL);
|
||||
m_bitmap.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
m_bitmap.bmi.bmiHeader.biPlanes = 1;
|
||||
m_bitmap.bmi.bmiHeader.biBitCount = 8;
|
||||
m_bitmap.bmi.bmiHeader.biCompression = BI_RGB;
|
||||
m_bitmap.bmi.bmiHeader.biSizeImage = 0;
|
||||
m_bitmap.bmi.bmiHeader.biClrUsed = 256;
|
||||
m_bitmap.bmi.bmiHeader.biClrImportant = 256;
|
||||
m_bitmap.bmi.bmiHeader.biWidth = BITMAP_W;
|
||||
m_bitmap.bmi.bmiHeader.biHeight = -BITMAP_H;
|
||||
m_bitmap.bmi.bmiHeader.biSizeImage = BITMAP_W*BITMAP_H;
|
||||
|
||||
memset(ge_fbuf,0,BITMAP_W*(BITMAP_H+1));
|
||||
fire_textcnt=0;
|
||||
|
||||
if (m_effect < 3)
|
||||
{
|
||||
unsigned char *t=(unsigned char *)m_bitmap.bmi.bmiColors;
|
||||
int x=255;
|
||||
int adj=!!m_effect;
|
||||
t[0]=t[1]=t[2]=0;
|
||||
t+=4;
|
||||
while (x)
|
||||
{
|
||||
if (m_effect == 2)
|
||||
{
|
||||
if (x > 128)
|
||||
{
|
||||
t[0]=0;
|
||||
t[1]=((256-x)*2)/3;
|
||||
t[2]=(256-x)*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
t[0]=256-x*2;
|
||||
t[1]=255/3 + ((256-x)*2)/3;
|
||||
t[2]=255;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int a=x*2;
|
||||
if (a>255) a=255;
|
||||
t[0]=a;
|
||||
t[2-adj]=a;
|
||||
a+=a;
|
||||
if (a > 255) a=255;
|
||||
t[1+adj]=a;
|
||||
}
|
||||
|
||||
t+=4;
|
||||
x--;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_effect==0)
|
||||
{
|
||||
//sine scroll
|
||||
struct
|
||||
{
|
||||
BITMAPINFO bmi;
|
||||
RGBQUAD more_bmiColors[1];
|
||||
LPVOID data;
|
||||
} m_bitmap;
|
||||
scrolldc = CreateCompatibleDC(NULL);
|
||||
m_bitmap.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
m_bitmap.bmi.bmiHeader.biPlanes = 1;
|
||||
m_bitmap.bmi.bmiHeader.biBitCount = 8;
|
||||
m_bitmap.bmi.bmiHeader.biCompression = BI_RGB;
|
||||
m_bitmap.bmi.bmiHeader.biSizeImage = 0;
|
||||
m_bitmap.bmi.bmiHeader.biClrUsed = 1;
|
||||
m_bitmap.bmi.bmiHeader.biClrImportant = 1;
|
||||
m_bitmap.bmi.bmiHeader.biWidth = 128;
|
||||
m_bitmap.bmi.bmiHeader.biHeight = -32;
|
||||
m_bitmap.bmi.bmiHeader.biSizeImage = 128*32;
|
||||
scrollbitmap = CreateDIBSection(scrolldc,&m_bitmap.bmi,DIB_RGB_COLORS, &m_bitmap.data, NULL, 0);
|
||||
SelectObject(scrolldc,scrollbitmap);
|
||||
SetBkMode(scrolldc,TRANSPARENT);
|
||||
scrolldib = (char *)m_bitmap.data;
|
||||
scrolloffs = 0;
|
||||
}
|
||||
|
||||
if (m_effect == 1)
|
||||
{
|
||||
int *t=BLOBPOINTS;
|
||||
int a=BLOBS_NPOINTS;
|
||||
while (a)
|
||||
{
|
||||
t[0]=(rand()&127) - 64;
|
||||
t[2]=(rand()&127) - 64;
|
||||
t[1]=t[3]=a;
|
||||
t+=4;
|
||||
a--;
|
||||
}
|
||||
}
|
||||
|
||||
if((m_effect >= 3 && m_effect <= 8)) //rotozooms
|
||||
{
|
||||
rototmp=(char *)malloc(65536+256);
|
||||
//generate noise texture
|
||||
memset(rototmp,0xd0,65536+256);
|
||||
__asm
|
||||
{
|
||||
mov cx,0ffffh
|
||||
xor ax,ax
|
||||
xor ebx,ebx
|
||||
xor dx,dx
|
||||
mov edi,[rototmp]
|
||||
TEXGEN:
|
||||
mov bx,cx
|
||||
add ax,cx
|
||||
rol ax,cl
|
||||
mov dh,al
|
||||
sar dh,5
|
||||
adc dl,dh
|
||||
adc dl,[edi+ebx+255]
|
||||
shr dl,1
|
||||
mov [edi+ebx],dl
|
||||
not bh
|
||||
mov [edi+ebx],dl
|
||||
loop TEXGEN
|
||||
}
|
||||
|
||||
if ((!!(GetAsyncKeyState(VK_SHIFT)&0x8000)) ^ (m_effect==5)) // secondary easter egg, hah!
|
||||
for (int x = 0; x < 256*256; x ++) rototmp[x] = 0x40 + ((x^(x>>8)) & 0x1F);
|
||||
|
||||
rototmp[0]=rototmp[1];
|
||||
rototmp[0xff00]=rototmp[0xff01];
|
||||
|
||||
//generate palette
|
||||
unsigned char *t=((unsigned char *)(&m_bitmap.bmi.bmiColors[0x40]));
|
||||
for(int i=0;i<0x20;i++)
|
||||
{
|
||||
int r,g,b;
|
||||
switch(m_effect)
|
||||
{
|
||||
case 3: r=i*4; g=i*5; b=i*8; break;
|
||||
case 4: r=i*4; g=i*7; b=i*8; break;
|
||||
case 5: r=i*8; g=i*2; b=i*2; break;
|
||||
case 6: r=i*6; g=i*8; b=i*6; break;
|
||||
case 7: r=i*8; g=i*6; b=i*8; break;
|
||||
case 8: r=i*6; g=i*6; b=i*8; break;
|
||||
}
|
||||
t[0]=b;
|
||||
t[1]=g;
|
||||
t[2]=r;
|
||||
t+=4;
|
||||
}
|
||||
}
|
||||
|
||||
m_hbm = CreateDIBSection(m_hdc,&m_bitmap.bmi,DIB_RGB_COLORS, &m_bitmap.data, NULL, 0);
|
||||
SelectObject(m_hdc,m_hbm);
|
||||
m_dib = (char *)m_bitmap.data;
|
||||
|
||||
SetTimer(hwndDlg,0x1234,35,NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
{
|
||||
int nomemcpy=0;
|
||||
static float inc=0;
|
||||
inc++;
|
||||
if (m_effect == 0) // oldsk00l sine scroll
|
||||
{
|
||||
double blah=3.14/BITMAP_W;
|
||||
double val1=1;
|
||||
double val2=(BITMAP_H-16)/2;
|
||||
static double vinc=0;
|
||||
__asm
|
||||
{
|
||||
mov edi, offset ge_fbuf
|
||||
mov ecx, BITMAP_W*BITMAP_H
|
||||
xor eax, eax
|
||||
rep stosb
|
||||
}
|
||||
|
||||
for(int j=0;j<8;j++) {
|
||||
for(int k=0;k<16;k++) {
|
||||
int col=255-k*(256/16);
|
||||
if(col<128) col=128+(128-col);
|
||||
memset(ge_fbuf+(k+(int)((BITMAP_H-16)*(cos(vinc+(j*8)*3.14/50)+1)/2))*BITMAP_W,col,BITMAP_W);
|
||||
}
|
||||
}
|
||||
|
||||
__asm
|
||||
{
|
||||
mov edi, offset ge_fbuf
|
||||
mov ecx, 0
|
||||
mov esi, dword ptr [scrolldib]
|
||||
|
||||
SINELOOP:
|
||||
mov [ge_tmp], ecx
|
||||
fild dword ptr [ge_tmp]
|
||||
fmul qword ptr [blah]
|
||||
fadd qword ptr [vinc]
|
||||
fcos
|
||||
fadd qword ptr [val1]
|
||||
fmul qword ptr [val2]
|
||||
fistp dword ptr [ge_tmp]
|
||||
mov eax, [ge_tmp]
|
||||
mov ebx, eax
|
||||
|
||||
mov edx, BITMAP_W
|
||||
mul edx
|
||||
|
||||
mov dh, bl
|
||||
push ecx
|
||||
mov ebx, 0
|
||||
mov ecx, 16
|
||||
|
||||
SINELOOP2:
|
||||
cmp byte ptr [esi+ebx],0
|
||||
je SINECONT
|
||||
|
||||
mov dl,0ffh
|
||||
sub dl,dh
|
||||
sub dl,cl
|
||||
|
||||
mov [edi+eax], dl
|
||||
SINECONT:
|
||||
add eax, BITMAP_W
|
||||
add ebx, 128
|
||||
loop SINELOOP2
|
||||
|
||||
pop ecx
|
||||
|
||||
inc esi
|
||||
inc edi
|
||||
|
||||
inc ecx
|
||||
cmp ecx, BITMAP_W
|
||||
jl SINELOOP
|
||||
|
||||
mov edi, [scrolldib]
|
||||
mov esi, edi
|
||||
inc esi
|
||||
mov ebx, 32
|
||||
SINESCROLL:
|
||||
mov ecx, 127
|
||||
rep movsb
|
||||
inc edi
|
||||
inc esi
|
||||
dec ebx
|
||||
jnz SINESCROLL
|
||||
}
|
||||
vinc+=0.2;
|
||||
scrolloffs++;
|
||||
if((scrolloffs&7)==7)
|
||||
{
|
||||
int o=scrolloffs/8;
|
||||
if(!scrolltext[o]) scrolloffs=0;
|
||||
else TextOutA(scrolldc,100,0,&scrolltext[o],1);
|
||||
}
|
||||
}
|
||||
else if (m_effect == 1) // blobs
|
||||
{
|
||||
int *blobptr=BLOBPOINTS;
|
||||
int i=BLOBS_NPOINTS*2;
|
||||
while (i--)
|
||||
{
|
||||
if (blobptr[0] > 0) blobptr[1]--;
|
||||
else blobptr[1]++;
|
||||
|
||||
int a=blobptr[1];
|
||||
if (rand()&1) a++;
|
||||
else a--;
|
||||
blobptr[0]+=a/8;
|
||||
|
||||
blobptr+=2;
|
||||
}
|
||||
|
||||
int y=BITMAP_H;
|
||||
unsigned char *p=(unsigned char *)ge_fbuf;
|
||||
while (y--)
|
||||
{
|
||||
int x=BITMAP_W;
|
||||
while (x--)
|
||||
{
|
||||
blobptr=BLOBPOINTS;
|
||||
i=BLOBS_NPOINTS;
|
||||
double sum=0.0;
|
||||
while (i--)
|
||||
{
|
||||
double as=(x-(BITMAP_W/2)) - blobptr[0];
|
||||
double bs=(y-(BITMAP_H/2)) - blobptr[2];
|
||||
sum+=sqrt(as*as + bs*bs);
|
||||
blobptr+=4;
|
||||
}
|
||||
sum *= 6.0/BLOBS_NPOINTS;
|
||||
int a=(int)sum;
|
||||
if (a > 0xff) a= 0xff;
|
||||
*p++=a;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_effect==2) //gayfire
|
||||
{
|
||||
unsigned char *p=(unsigned char *)ge_fbuf;
|
||||
int x;
|
||||
unsigned char *t=p + BITMAP_W*BITMAP_H;
|
||||
for (x = 0; x < BITMAP_W; x ++)
|
||||
{
|
||||
int a=*t - 10;
|
||||
if ((rand()&0x7) == 7) a+=100;
|
||||
if (a < 0) a=0;
|
||||
else if (a > 192) a=192;
|
||||
*t++=a;//rand()&0xf0;
|
||||
}
|
||||
int y;
|
||||
for (y = 0; y < BITMAP_H; y ++)
|
||||
{
|
||||
*p++=p[0]/4 + p[BITMAP_W]/2 + p[BITMAP_W+1]/4;
|
||||
|
||||
for (x = 1; x < BITMAP_W-1; x ++)
|
||||
*p++=p[0]/4 + p[BITMAP_W]/4 + p[BITMAP_W-1]/4 + p[BITMAP_W+1]/4;
|
||||
|
||||
*p++=p[0]/4 + p[BITMAP_W]/2 + p[BITMAP_W-1]/4;
|
||||
}
|
||||
if (fire_textcnt-- <= 0)
|
||||
{
|
||||
memcpy(m_dib,ge_fbuf,BITMAP_W*BITMAP_H);
|
||||
SetBkMode(m_hdc,TRANSPARENT);
|
||||
SetTextColor(m_hdc,RGB(255,255,255));
|
||||
RECT r={0,0,BITMAP_W,BITMAP_H};
|
||||
DrawTextA(m_hdc,fire_texts[fire_textpos%(sizeof(fire_texts)/sizeof(fire_texts[0]))],-1,&r,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
|
||||
if (fire_textcnt < -30)
|
||||
{
|
||||
memcpy(ge_fbuf,m_dib,BITMAP_W*BITMAP_H);
|
||||
fire_textpos++;
|
||||
fire_textcnt=30;
|
||||
}
|
||||
else nomemcpy=1;
|
||||
}
|
||||
}
|
||||
else if (m_effect == 3) //rotozoom
|
||||
{
|
||||
char *p=ge_fbuf;
|
||||
static float angle=0;
|
||||
for(int j=-32;j<32;j++)
|
||||
for(int i=-50;i<50;i++)
|
||||
{
|
||||
//rotozoom
|
||||
double x=(i*cosf(angle)-j*sinf(angle))*(2+cosf(angle*1.4f));
|
||||
double y=(i*sinf(angle)+j*cosf(angle))*(2+cosf(angle*1.4f));
|
||||
//slime
|
||||
x+=cos(angle*x)*4;
|
||||
y+=sin(angle*y)*4;
|
||||
int x2=(int)x & 0xff;
|
||||
int y2=(int)y & 0xff;
|
||||
*p++=rototmp[256*y2+x2];
|
||||
}
|
||||
|
||||
angle+=0.01f;
|
||||
}
|
||||
else if (m_effect == 4) //rotozoom 2
|
||||
{
|
||||
char *p=ge_fbuf;
|
||||
double angle=cos(inc*0.01f)*2;
|
||||
for(int j=-32;j<32;j++)
|
||||
for(int i=-50;i<50;i++)
|
||||
{
|
||||
//position
|
||||
double x=i-cos(inc*0.013f)*64;
|
||||
double y=j+sin(inc*0.013f)*64;
|
||||
|
||||
//slime
|
||||
x+=cos((angle+i)*50)*cos(angle)*4;
|
||||
y+=sin((angle+j)*50)*cos(angle)*4;
|
||||
|
||||
//rotozoom
|
||||
double x3=(x*cos(angle)-y*sin(angle))*(2+cos(angle*1.4f));
|
||||
double y3=(x*sin(angle)+y*cos(angle))*(2+cos(angle*1.4f));
|
||||
|
||||
int x2=(int)x3 & 0xff;
|
||||
int y2=(int)y3 & 0xff;
|
||||
*p++=rototmp[256*y2+x2];
|
||||
}
|
||||
}
|
||||
else if (m_effect == 5) //3d rotozoom
|
||||
{
|
||||
char *p=ge_fbuf;
|
||||
static float angle=0;
|
||||
const double b=50;
|
||||
for(int j=-32;j<32;j++)
|
||||
for(int i=-50;i<50;i++)
|
||||
{
|
||||
//rotozoom
|
||||
double x=(i*cos(angle)+j*sin(angle));//*(2+cos(angle*1.4f));
|
||||
double y=(i*sin(angle)-j*cos(angle));//*(2+cos(angle*1.4f));
|
||||
//gay z-projection
|
||||
x*=b/(((double)j+32));
|
||||
y*=b/(((double)j+32));
|
||||
//position
|
||||
x-=cos(inc*0.013f)*64;
|
||||
y+=sin(inc*0.013f)*64;
|
||||
|
||||
int x2=(int)x & 0xff;
|
||||
int y2=(int)y & 0xff;
|
||||
|
||||
char c=rototmp[256*y2+x2];
|
||||
*p++=0x40+((c-0x40)*(j+32)/56);
|
||||
}
|
||||
|
||||
angle+=0.01f;
|
||||
//b++;
|
||||
}
|
||||
else if (m_effect == 6) //tunnel
|
||||
{
|
||||
const double TINYNUM=1.0E-6;
|
||||
const double CONE_RADIUS=128;
|
||||
const double FOV=120.0;
|
||||
#define sqr(a) ((a)*(a))
|
||||
|
||||
char *p=ge_fbuf;
|
||||
for(int y=-32;y<32;y++)
|
||||
for(int x=-50;x<50;x++)
|
||||
{
|
||||
double originx=cos(inc*0.025f)*20;
|
||||
double originy=sin(inc*0.04f)*20;
|
||||
double originz=inc*4;
|
||||
double dirx=x/FOV;
|
||||
double diry=y/FOV;
|
||||
double dirz=1;
|
||||
|
||||
//normalize dir vector
|
||||
{
|
||||
double l=1.0f/sqrt(sqr(dirx)+sqr(diry)+sqr(dirz));
|
||||
dirx*=l;
|
||||
diry*=l;
|
||||
dirz*=l;
|
||||
}
|
||||
|
||||
//y-axis rotation
|
||||
{
|
||||
double rot=inc*0.015f;
|
||||
double dirx2=dirx*cos(rot)+dirz*sin(rot);
|
||||
dirz=dirx*sin(rot)-dirz*cos(rot);
|
||||
dirx=dirx2;
|
||||
}
|
||||
|
||||
//tunnel algo shit
|
||||
double a=sqr(dirx)+sqr(diry);
|
||||
double b=2*(originx*dirx + originy*diry);
|
||||
double c=sqr(originx)+sqr(originy)-sqr(CONE_RADIUS);
|
||||
double delta=sqrt(sqr(b)-(4*a*c));
|
||||
|
||||
double t1=(-b+delta)/(2*a+TINYNUM);
|
||||
double t2=(-b-delta)/(2*a+TINYNUM);
|
||||
|
||||
double t=t1>0?t1:t2;
|
||||
|
||||
double intx=originx+dirx*t;
|
||||
double inty=originy+diry*t;
|
||||
double intz=originz+dirz*t;
|
||||
|
||||
//tex. coords
|
||||
int u=(int)(fabs(intz)*0.6);
|
||||
int v=(int)(fabs(atan2(inty,intx)*256/3.14159265));
|
||||
|
||||
//depth
|
||||
t=20000.0/t;
|
||||
int z=(int)(t>63?63:t);
|
||||
|
||||
u&=0xff;
|
||||
v&=0xff;
|
||||
z&=0xff;
|
||||
|
||||
{
|
||||
char c=rototmp[256*u+v];
|
||||
*p++=0x40+((c-0x40)*z/64);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_effect==7) //washing machine
|
||||
{
|
||||
char *p=ge_fbuf;
|
||||
for(int j=-32;j<32;j++)
|
||||
for(int i=-50;i<50;i++)
|
||||
{
|
||||
double dist=sqrt(double(sqr(i)+sqr(j))); // pythagoras rules :)
|
||||
double angle=cos(dist*0.05f)*(cos(inc*0.1f)) + inc*0.07f;
|
||||
//rotozoom
|
||||
double x=(i*cos(angle)-j*sin(angle));
|
||||
double y=(i*sin(angle)+j*cos(angle));
|
||||
int x2=(int)x & 0xff;
|
||||
int y2=(int)y & 0xff;
|
||||
*p++=rototmp[256*y2+x2];
|
||||
}
|
||||
}
|
||||
else if(m_effect==8) //reflection-like(?) effect
|
||||
{
|
||||
char *p=ge_fbuf;
|
||||
for(int j=-32;j<32;j++)
|
||||
for(int i=-50;i<50;i++)
|
||||
{
|
||||
double dist=sqrt(double(sqr(i)+sqr(j)));
|
||||
double zoom=cos(dist*0.05f)*(cos(inc*0.02f)*8)+1;
|
||||
//rotozoom
|
||||
double x=i*zoom+inc;
|
||||
double y=j*zoom+inc;
|
||||
int x2=(int)x & 0xff;
|
||||
int y2=(int)y & 0xff;
|
||||
*p++=rototmp[256*x2+y2];
|
||||
}
|
||||
}
|
||||
|
||||
if (!nomemcpy) memcpy(m_dib,ge_fbuf,BITMAP_W*BITMAP_H);
|
||||
if (hwndDlg != NULL)
|
||||
{
|
||||
HDC h = GetDC(hwndDlg);
|
||||
BitBlt(h, 11, 11, BITMAP_W, BITMAP_H, m_hdc, 0, 0, SRCCOPY);
|
||||
ReleaseDC(hwndDlg, h);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_about(HWND hwnd, HINSTANCE hinst) {
|
||||
#ifndef MODAL_ABOUT
|
||||
if(about_hwnd) {
|
||||
SetForegroundWindow(about_hwnd);
|
||||
return;
|
||||
}
|
||||
about_hwnd=CreateDialogParam((!hinst?g_hInstance:hinst),MAKEINTRESOURCE(IDD_ABOUT),hwnd,aboutProc,(LPARAM)hinst);
|
||||
ShowWindow(about_hwnd,SW_SHOW);
|
||||
#else
|
||||
#ifdef LOC_MODAL_ABOUT
|
||||
WASABI_API_DIALOGBOXPARAMW(IDD_ABOUT,hwnd,aboutProc,(LPARAM)hinst);
|
||||
#else
|
||||
DialogBoxParam((!hinst?g_hInstance:hinst),MAKEINTRESOURCE(IDD_ABOUT),hwnd,aboutProc,(LPARAM)hinst);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif//_ABOUT_H_
|
575
Src/nsv/nsvplay/audiostub.cpp
Normal file
575
Src/nsv/nsvplay/audiostub.cpp
Normal file
@ -0,0 +1,575 @@
|
||||
#include <windows.h>
|
||||
#include "audiostub.h"
|
||||
|
||||
#define CAPTION "NSV Player Sound Output Error"
|
||||
#define MAX(x,y) (( y ) < ( x ) ? ( x ) : ( y ))
|
||||
#define MIN(x,y) (( x ) < ( y ) ? ( x ) : ( y ))
|
||||
|
||||
#define S_MINSIZE (1<<28)
|
||||
#define MAX_NUM_BLOCKS 8
|
||||
|
||||
#define NUM_BLOCKS 8
|
||||
#define BUFSIZE_MS 1500
|
||||
|
||||
#define BLOCKSIZE_MAX 32768
|
||||
#define BLOCKSIZE_MIN 8192
|
||||
|
||||
int g_audio_use_mixer=0;
|
||||
|
||||
class PCM_AudioOut : public IAudioOutput
|
||||
{
|
||||
public:
|
||||
PCM_AudioOut(int samplerate, int numchannels, int bitspersamp);
|
||||
~PCM_AudioOut();
|
||||
|
||||
int canwrite(); // returns bytes writeable
|
||||
void write(void *_buf, int len);
|
||||
unsigned int getpos();
|
||||
unsigned int getwritepos();
|
||||
void flush(unsigned int time_ms);
|
||||
void pause(int pause);
|
||||
int isplaying(void);
|
||||
void setvolume(int volume);
|
||||
void setpan(int pan);
|
||||
|
||||
int open_success() { return init; }
|
||||
void getdescstr(char *buf)
|
||||
{
|
||||
*buf=0;
|
||||
if (g_srate && g_nch) wsprintf(buf,"%dkHz %s",g_srate/1000,g_nch==2?"stereo":"mono");
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD ThreadP();
|
||||
|
||||
void _setvol(void);
|
||||
|
||||
static DWORD WINAPI _threadproc(LPVOID p);
|
||||
static void CALLBACK cbFunc(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)
|
||||
{
|
||||
if (uMsg == WOM_DONE) { ReleaseSemaphore((HANDLE)dwInstance,1,NULL);}
|
||||
}
|
||||
void do_set_blocksizes(void);
|
||||
void do_samples_altvol(char *in, int blen);
|
||||
|
||||
int init;
|
||||
|
||||
int min_blocksize;
|
||||
int max_blocksize;
|
||||
|
||||
int ispcnt;
|
||||
int num_blocks;
|
||||
|
||||
char *g_buffer, *g_buffer_write, *g_buffer_read;
|
||||
int g_buffer_length, g_buffer_valid,g_buffer_inlength;
|
||||
HWAVEOUT g_hWaveOut;
|
||||
WAVEHDR g_wave_headers[MAX_NUM_BLOCKS];
|
||||
int g_bps,g_nch,g_srate;
|
||||
volatile int g_pause, g_wavecnt, g_prebuf,g_writeall, g_quit_flag,g_writetime_bytes, g_outtime_bytes, g_outtime_interp;
|
||||
|
||||
HANDLE g_hSem,g_hEvent, g_hThread;
|
||||
CRITICAL_SECTION g_cs;
|
||||
|
||||
int g_bytes_per_sec;
|
||||
int a_v,a_p;
|
||||
|
||||
unsigned char *g_vol_table;
|
||||
};
|
||||
|
||||
|
||||
PCM_AudioOut::PCM_AudioOut(int samplerate, int numchannels, int bitspersamp)
|
||||
{
|
||||
init=0;
|
||||
a_v=255;
|
||||
a_p=0;
|
||||
num_blocks=0;
|
||||
|
||||
g_buffer_valid=g_buffer_inlength=0;
|
||||
g_hWaveOut=NULL;
|
||||
memset(g_wave_headers,0,sizeof(g_wave_headers));
|
||||
|
||||
g_hSem=g_hEvent=g_hThread=0;
|
||||
|
||||
int x;
|
||||
DWORD id;
|
||||
MMRESULT res;
|
||||
WAVEFORMATEX wfx={WAVE_FORMAT_PCM,numchannels,samplerate,samplerate*numchannels*(bitspersamp/8),
|
||||
numchannels*(bitspersamp/8),bitspersamp};
|
||||
|
||||
g_bps=bitspersamp;
|
||||
g_nch=numchannels;
|
||||
g_srate=samplerate;
|
||||
g_bytes_per_sec=wfx.nAvgBytesPerSec;
|
||||
|
||||
{
|
||||
char *p=(char*)g_wave_headers;
|
||||
int n=sizeof(g_wave_headers);
|
||||
while (n--) *p++=0;
|
||||
}
|
||||
g_buffer_length = MulDiv(g_bytes_per_sec, BUFSIZE_MS, 1000);
|
||||
g_buffer_length &= ~1023;
|
||||
if (g_buffer_length < 4096) g_buffer_length=4096;
|
||||
|
||||
g_buffer=(char *)GlobalAlloc(GMEM_FIXED,g_buffer_length+min(65536,g_buffer_length));
|
||||
if (g_buffer == NULL)
|
||||
{
|
||||
MessageBox(NULL,"Error allocating buffer", CAPTION,MB_OK|MB_ICONSTOP);
|
||||
return;
|
||||
}
|
||||
|
||||
g_prebuf=g_buffer_length/4;
|
||||
g_buffer_read=g_buffer_write=g_buffer;
|
||||
g_wavecnt=g_pause=g_writeall=g_buffer_valid=g_writetime_bytes=g_outtime_bytes=g_buffer_inlength=0;
|
||||
g_quit_flag=0;
|
||||
|
||||
g_vol_table=NULL;
|
||||
|
||||
do_set_blocksizes();
|
||||
|
||||
g_hSem=CreateSemaphore(NULL,0,256,NULL);
|
||||
for (x = 0; (res=waveOutOpen(&g_hWaveOut,WAVE_MAPPER,&wfx,(DWORD)cbFunc,(DWORD)g_hSem,CALLBACK_FUNCTION))==MMSYSERR_ALLOCATED && x<10; x ++)
|
||||
Sleep(100);
|
||||
if (res != MMSYSERR_NOERROR)
|
||||
{
|
||||
char t[512];
|
||||
waveOutGetErrorText(res,t,sizeof(t));
|
||||
MessageBox(NULL,t, CAPTION,MB_OK|MB_ICONSTOP);
|
||||
GlobalFree((HGLOBAL) g_buffer);
|
||||
CloseHandle(g_hSem);
|
||||
g_buffer = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
ispcnt=0;
|
||||
g_outtime_interp=GetTickCount();
|
||||
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||
InitializeCriticalSection(&g_cs);
|
||||
|
||||
g_hThread=CreateThread(NULL,0,_threadproc,(void*)this,0,&id);
|
||||
SetThreadPriority(g_hThread,THREAD_PRIORITY_HIGHEST);
|
||||
|
||||
init=1;
|
||||
}
|
||||
|
||||
|
||||
void PCM_AudioOut::do_set_blocksizes(void)
|
||||
{
|
||||
int t,t2,t4;
|
||||
t=(MulDiv(BLOCKSIZE_MIN,g_bytes_per_sec,44100)+1023)&~1023;
|
||||
if (t<1024) t=1024;
|
||||
if (t>32768) t=32768;
|
||||
|
||||
t2=(MulDiv(BLOCKSIZE_MAX,g_bytes_per_sec,44100*4)+1023)&~1023;
|
||||
if (t2 < t) t2 = t;
|
||||
if (t2 > 65536) t2=65536;
|
||||
|
||||
t4 = NUM_BLOCKS;
|
||||
|
||||
num_blocks=t4;
|
||||
max_blocksize=t2;
|
||||
min_blocksize=t;
|
||||
}
|
||||
|
||||
|
||||
PCM_AudioOut::~PCM_AudioOut(void)
|
||||
{
|
||||
if (init)
|
||||
{
|
||||
int x;
|
||||
g_quit_flag=1;
|
||||
SetEvent(g_hEvent);
|
||||
while (g_quit_flag == 1) Sleep(70);
|
||||
|
||||
waveOutReset(g_hWaveOut);
|
||||
|
||||
for (x = 0; x < MAX_NUM_BLOCKS; x++)
|
||||
if (g_wave_headers[x].dwFlags & WHDR_PREPARED)
|
||||
waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
|
||||
if (waveOutClose(g_hWaveOut) != MMSYSERR_NOERROR)
|
||||
{
|
||||
MessageBox(NULL,"Error closing sound device.",CAPTION,MB_OK);
|
||||
}
|
||||
if (g_buffer) GlobalFree((HGLOBAL) g_buffer);
|
||||
DeleteCriticalSection(&g_cs);
|
||||
CloseHandle(g_hThread);
|
||||
CloseHandle(g_hSem);
|
||||
CloseHandle(g_hEvent);
|
||||
|
||||
if(g_vol_table) GlobalFree((HGLOBAL)g_vol_table);
|
||||
}
|
||||
}
|
||||
|
||||
void PCM_AudioOut::write(void *_buf, int len)
|
||||
{
|
||||
char *buf=(char *)_buf;
|
||||
int l2;
|
||||
if (len > 8192) len=8192;
|
||||
l2=(g_buffer_write+len)-(g_buffer+g_buffer_length);
|
||||
if (len <= 0 || !buf)
|
||||
{
|
||||
g_writeall=1;
|
||||
//g_prebuf=0;
|
||||
SetEvent(g_hEvent);
|
||||
return;
|
||||
}
|
||||
ispcnt=0;
|
||||
g_writeall=0;
|
||||
if (l2 > 0)
|
||||
{
|
||||
int l1=len-l2;
|
||||
memcpy(g_buffer_write,buf,l1);
|
||||
memcpy(g_buffer,buf+l1,l2);
|
||||
g_buffer_write=g_buffer+l2;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(g_buffer_write,buf,len);
|
||||
g_buffer_write += len;
|
||||
if (g_buffer_write == g_buffer+g_buffer_length) g_buffer_write=g_buffer;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&g_cs);
|
||||
g_buffer_valid+=len;
|
||||
LeaveCriticalSection(&g_cs);
|
||||
g_writetime_bytes+=len;
|
||||
if (g_wavecnt < num_blocks)
|
||||
{
|
||||
SetEvent(g_hEvent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int PCM_AudioOut::canwrite(void)
|
||||
{
|
||||
int t=(g_buffer_length-g_buffer_valid);
|
||||
if (g_wavecnt==0)
|
||||
{
|
||||
SetEvent(g_hEvent);
|
||||
}
|
||||
if (t>8192) t=8192; // RG: since write() caps the # of bytes at 8192, this should reflect that! otherwise, if we call write() with too many bytes, it throws the extra away and we'll never know it.
|
||||
return t;
|
||||
}
|
||||
|
||||
int PCM_AudioOut::isplaying(void)
|
||||
{
|
||||
if (g_wavecnt==0)
|
||||
{
|
||||
SetEvent(g_hEvent);
|
||||
}
|
||||
if (ispcnt < 7) ispcnt++;
|
||||
if (g_buffer_valid < MIN(g_buffer_length/2,min_blocksize) && ispcnt==7)
|
||||
{
|
||||
g_writeall=1;
|
||||
g_prebuf=0;
|
||||
}
|
||||
return (g_wavecnt>0) || (g_buffer_valid>0);
|
||||
}
|
||||
|
||||
void PCM_AudioOut::pause(int pause)
|
||||
{
|
||||
if (g_hWaveOut)
|
||||
{
|
||||
int lastp=g_pause;
|
||||
g_pause=pause;
|
||||
if (pause == lastp) return;
|
||||
if (g_pause)
|
||||
waveOutPause(g_hWaveOut);
|
||||
else
|
||||
{
|
||||
waveOutRestart(g_hWaveOut);
|
||||
g_outtime_interp=GetTickCount();
|
||||
SetEvent(g_hEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PCM_AudioOut::_setvol(void)
|
||||
{
|
||||
DWORD vol, vo2, gv;
|
||||
if (g_hWaveOut)
|
||||
{
|
||||
a_v=MIN(255,MAX(a_v,0));
|
||||
a_p=MIN(127,MAX(a_p,-127));
|
||||
|
||||
vo2 = vol = (a_v*65535) / 255;
|
||||
|
||||
if (a_p > 0)
|
||||
{
|
||||
vol *= (127-a_p);
|
||||
vol /= 127;
|
||||
}
|
||||
else if (a_p < 0)
|
||||
{
|
||||
vo2 *= (127+a_p);
|
||||
vo2 /= 127;
|
||||
}
|
||||
gv=vol|(vo2<<16);
|
||||
if(g_audio_use_mixer) {
|
||||
if(g_vol_table) {
|
||||
EnterCriticalSection(&g_cs);
|
||||
GlobalFree((HGLOBAL)g_vol_table);
|
||||
g_vol_table=NULL;
|
||||
LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
waveOutSetVolume(g_hWaveOut,gv);
|
||||
} else {
|
||||
EnterCriticalSection(&g_cs);
|
||||
if(!g_vol_table) {
|
||||
int l=(g_bps==8)?512:(4*32769);
|
||||
g_vol_table=(unsigned char *)GlobalAlloc(GPTR,l);
|
||||
}
|
||||
//compute volume lookup table
|
||||
int x;
|
||||
if (g_bps==8) {
|
||||
if (g_nch==1) for (x = 0; x < 256; x ++) g_vol_table[x] = (x*a_v)/256;
|
||||
else for (x = 0; x < 256; x ++)
|
||||
{
|
||||
g_vol_table[x] = (x*(int)vol)/65536;
|
||||
g_vol_table[x+256] = (x*(int)vo2)/65536;
|
||||
}
|
||||
} else {
|
||||
short *vol_tab16 = (short *)g_vol_table;
|
||||
if (g_nch==1) for (x = 0; x < 32769; x ++) vol_tab16[x] = -(x*a_v)/256;
|
||||
else for (x = 0; x < 32769; x ++)
|
||||
{
|
||||
vol_tab16[x] = -(x*(int)vol)/65536;
|
||||
vol_tab16[x+32769] = -(x*(int)vo2)/65536;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PCM_AudioOut::flush(unsigned int time_ms)
|
||||
{
|
||||
int x;
|
||||
EnterCriticalSection(&g_cs);
|
||||
g_outtime_bytes=g_writetime_bytes=MulDiv(time_ms,g_bytes_per_sec,1000);
|
||||
waveOutReset(g_hWaveOut);
|
||||
for (x = 0; x < MAX_NUM_BLOCKS; x++)
|
||||
if ((g_wave_headers[x].dwFlags & WHDR_PREPARED))
|
||||
{
|
||||
waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
|
||||
g_wave_headers[x].dwFlags =0;
|
||||
}
|
||||
while (WaitForSingleObject(g_hSem,0)==WAIT_OBJECT_0);
|
||||
g_prebuf=g_buffer_length/8;
|
||||
g_buffer_read=g_buffer_write=g_buffer;
|
||||
g_writeall=g_wavecnt=g_buffer_valid=g_buffer_inlength=0;
|
||||
ispcnt=0;
|
||||
LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
unsigned int PCM_AudioOut::getwritepos(void)
|
||||
{
|
||||
return MulDiv(g_writetime_bytes,1000,g_bytes_per_sec);
|
||||
}
|
||||
|
||||
unsigned int PCM_AudioOut::getpos(void)
|
||||
{
|
||||
unsigned int t;
|
||||
if (!g_pause)
|
||||
{
|
||||
t=GetTickCount()-g_outtime_interp;
|
||||
if (t > 1000) t=1000;
|
||||
}
|
||||
else t=0;
|
||||
return t+MulDiv(g_outtime_bytes,1000,g_bytes_per_sec);
|
||||
}
|
||||
|
||||
DWORD WINAPI PCM_AudioOut::_threadproc(LPVOID p)
|
||||
{
|
||||
return ((PCM_AudioOut *)p)->ThreadP();
|
||||
}
|
||||
|
||||
DWORD PCM_AudioOut::ThreadP()
|
||||
{
|
||||
HANDLE hs[2]={g_hSem,g_hEvent};
|
||||
while (1)
|
||||
{
|
||||
int i;
|
||||
i=WaitForMultipleObjects(2,hs,FALSE,INFINITE);
|
||||
if (g_quit_flag) break;
|
||||
if (i == WAIT_OBJECT_0)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < MAX_NUM_BLOCKS && !(g_wave_headers[x].dwFlags & WHDR_DONE); x++);
|
||||
if (x < MAX_NUM_BLOCKS)
|
||||
{
|
||||
EnterCriticalSection(&g_cs);
|
||||
if (g_wave_headers[x].dwFlags & WHDR_DONE)
|
||||
{
|
||||
int r=g_wave_headers[x].dwBufferLength;
|
||||
g_outtime_interp=GetTickCount();
|
||||
g_buffer_valid -=r;
|
||||
g_buffer_inlength-=r;
|
||||
g_outtime_bytes +=r;
|
||||
waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
|
||||
g_wave_headers[x].dwFlags=0;
|
||||
g_wavecnt--;
|
||||
i++;
|
||||
}
|
||||
LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
}
|
||||
if (i == WAIT_OBJECT_0+1 && !g_pause)
|
||||
{
|
||||
int l;
|
||||
int m;
|
||||
int t=num_blocks;
|
||||
EnterCriticalSection(&g_cs);
|
||||
l=g_buffer_valid-g_buffer_inlength;
|
||||
LeaveCriticalSection(&g_cs);
|
||||
again:
|
||||
if (g_quit_flag) break;
|
||||
if (g_writeall && l<max_blocksize)
|
||||
{
|
||||
ispcnt=0;
|
||||
g_writeall=0;
|
||||
m=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m=MAX(MIN(g_buffer_length/2,min_blocksize),g_prebuf);
|
||||
l&=~1023;
|
||||
}
|
||||
if (l >= m && g_wavecnt < t)
|
||||
{
|
||||
int x;
|
||||
if (l > max_blocksize) l=max_blocksize;
|
||||
for (x = 0; x < t && (g_wave_headers[x].dwFlags & WHDR_PREPARED); x++);
|
||||
if (x < t)
|
||||
{
|
||||
int ml=(g_buffer+g_buffer_length)-g_buffer_read;
|
||||
if (l > g_buffer_length) l=g_buffer_length;
|
||||
if (l>ml)
|
||||
{
|
||||
int addlen=l-ml;
|
||||
if (addlen > 65536) addlen=65536;
|
||||
if (addlen > g_buffer_length) addlen=g_buffer_length;
|
||||
memcpy(g_buffer+g_buffer_length,g_buffer,addlen);
|
||||
}
|
||||
|
||||
g_wave_headers[x].dwBufferLength=l;
|
||||
g_wave_headers[x].lpData=g_buffer_read;
|
||||
|
||||
if (waveOutPrepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0])) == MMSYSERR_NOERROR)
|
||||
{
|
||||
do_samples_altvol(g_wave_headers[x].lpData,g_wave_headers[x].dwBufferLength);
|
||||
|
||||
if (waveOutWrite(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0])) == MMSYSERR_NOERROR)
|
||||
{
|
||||
g_prebuf=0;
|
||||
|
||||
g_wavecnt++;
|
||||
|
||||
g_buffer_inlength += l;
|
||||
g_buffer_read += l;
|
||||
|
||||
if (g_buffer_read >= g_buffer+g_buffer_length) g_buffer_read-=g_buffer_length;
|
||||
|
||||
if (g_wavecnt < t)
|
||||
{
|
||||
EnterCriticalSection(&g_cs);
|
||||
l=g_buffer_valid-g_buffer_inlength;
|
||||
LeaveCriticalSection(&g_cs);
|
||||
if (l >= m) goto again;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
|
||||
g_wave_headers[x].dwFlags=0;
|
||||
}
|
||||
}
|
||||
else g_wave_headers[x].dwFlags=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g_quit_flag=2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PCM_AudioOut::do_samples_altvol(char *in, int blen)
|
||||
{
|
||||
if ((a_v != 255 || a_p) && g_vol_table)
|
||||
{
|
||||
EnterCriticalSection(&g_cs);
|
||||
if (g_bps == 8)
|
||||
{
|
||||
unsigned char *i=(unsigned char *)in;
|
||||
int x = blen;
|
||||
if (g_nch==1)
|
||||
{
|
||||
while (x--) { *i = g_vol_table[*i]; i ++; }
|
||||
}
|
||||
else
|
||||
{
|
||||
x>>=1;
|
||||
while (x--)
|
||||
{
|
||||
i[0] = g_vol_table[i[0]];
|
||||
i[1] = g_vol_table[i[1] + 256];
|
||||
i+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (g_bps == 16)
|
||||
{
|
||||
short *i = (short *) in;
|
||||
short *tab= (short *)g_vol_table;
|
||||
int x = blen>>1;
|
||||
if (g_nch==1)
|
||||
{
|
||||
while (x--)
|
||||
{
|
||||
int a = i[0];
|
||||
if (a <= 0) i[0] = tab[-a];
|
||||
else i[0] = -tab[a];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x>>=1;
|
||||
while (x--)
|
||||
{
|
||||
int a = i[0];
|
||||
if (a <= 0) i[0] = tab[-a];
|
||||
else i[0] = -tab[a];
|
||||
a=i[1];
|
||||
if (a <= 0) i[1] = tab[32769-a];
|
||||
else i[1] = -tab[32769+a];
|
||||
i+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
}
|
||||
|
||||
void PCM_AudioOut::setvolume(int volume)
|
||||
{
|
||||
if (volume >= 0 && volume <= 255) a_v=volume;
|
||||
_setvol();
|
||||
}
|
||||
|
||||
void PCM_AudioOut::setpan(int pan)
|
||||
{
|
||||
if (pan >= -255 && pan <= 255) a_p=pan;
|
||||
_setvol();
|
||||
}
|
||||
|
||||
|
||||
IAudioOutput *PCMOUT_CREATE(unsigned int outfmt[8])
|
||||
{
|
||||
if (outfmt[0] != NSV_MAKETYPE('P','C','M',' ') ||
|
||||
!outfmt[1] || !outfmt[2] || !outfmt[3]) return NULL;
|
||||
PCM_AudioOut *p=new PCM_AudioOut(outfmt[1],outfmt[2],outfmt[3]);
|
||||
if (p->open_success()) return p;
|
||||
delete p;
|
||||
return NULL;
|
||||
}
|
8
Src/nsv/nsvplay/audiostub.h
Normal file
8
Src/nsv/nsvplay/audiostub.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _AUDIOSTUB_H_
|
||||
#define _AUDIOSTUB_H_
|
||||
|
||||
#include "../dec_if.h"
|
||||
|
||||
IAudioOutput *PCMOUT_CREATE(unsigned int outfmt[8]);
|
||||
|
||||
#endif
|
675
Src/nsv/nsvplay/decoders.cpp
Normal file
675
Src/nsv/nsvplay/decoders.cpp
Normal file
@ -0,0 +1,675 @@
|
||||
#include <windows.h>
|
||||
#include "api.h"
|
||||
#include "main.h"
|
||||
#include "vfw.h"
|
||||
#include <api/service/services.h>
|
||||
#include "../nsv/svc_nsvFactory.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include "../../Winamp/in2.h"
|
||||
extern In_Module mod;
|
||||
|
||||
// you should probably override these in your project settings
|
||||
|
||||
// builtin decoders
|
||||
//#define BUILTIN_MP3_SUPPORT
|
||||
//#define BUILTIN_VP3_SUPPORT
|
||||
//#define BUILTIN_DIVX_SUPPORT
|
||||
//#define BUILTIN_PCM_SUPPORT
|
||||
//#define BUILTIN_VFW_SUPPORT
|
||||
|
||||
// support dll decoders?
|
||||
//#define DLL_DECODER_SUPPORT
|
||||
|
||||
//#define DLL_DECODER_SUPPORT_NOCURDIR
|
||||
|
||||
#ifdef WINAMP_PLUGIN
|
||||
# ifndef DLL_DECODER_SUPPORT
|
||||
# define DLL_DECODER_SUPPORT
|
||||
# endif
|
||||
# ifndef DLL_DECODER_SUPPORT_NOCURDIR
|
||||
# define DLL_DECODER_SUPPORT_NOCURDIR
|
||||
# endif
|
||||
# ifndef DLL_DECODER_SUPPORT_IN_
|
||||
# define DLL_DECODER_SUPPORT_IN_
|
||||
# endif
|
||||
# ifndef BUILTIN_PCM_SUPPORT
|
||||
# define BUILTIN_PCM_SUPPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef BUILTIN_VP3_SUPPORT
|
||||
#include "vp3stub.h"
|
||||
#endif
|
||||
#ifdef BUILTIN_VP5_SUPPORT
|
||||
#include "vp5stub.h"
|
||||
#endif
|
||||
#ifdef BUILTIN_MP3_SUPPORT
|
||||
#include "mp3stub.h"
|
||||
#endif
|
||||
|
||||
#ifdef BUILTIN_VFW_SUPPORT
|
||||
|
||||
class Gen_Decoder : public IVideoDecoder {
|
||||
public:
|
||||
Gen_Decoder(int w, int h);
|
||||
~Gen_Decoder();
|
||||
int decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf);
|
||||
void flush() { }
|
||||
|
||||
int m_err;
|
||||
|
||||
int width,height;
|
||||
BITMAPINFO gen_bmo,gen_bmi;
|
||||
HIC gen_hic;
|
||||
unsigned char *vidbufdec;
|
||||
};
|
||||
|
||||
Gen_Decoder::Gen_Decoder(int w, int h)
|
||||
{
|
||||
width=w;
|
||||
height=h;
|
||||
m_err=0;
|
||||
gen_hic=0;
|
||||
vidbufdec=(unsigned char*)malloc(sizeof(YV12_PLANES) + w*h*3/2);
|
||||
}
|
||||
|
||||
Gen_Decoder::~Gen_Decoder()
|
||||
{
|
||||
if (gen_hic)
|
||||
{
|
||||
ICDecompressEnd(gen_hic);
|
||||
ICClose(gen_hic);
|
||||
}
|
||||
free(vidbufdec);
|
||||
}
|
||||
|
||||
|
||||
int Gen_Decoder::decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf)
|
||||
{
|
||||
*out_type=NSV_MAKETYPE('Y','V','1','2');
|
||||
gen_bmi.bmiHeader.biSizeImage = in_len;
|
||||
if(ICERR_OK == ICDecompress(gen_hic,0,(BITMAPINFOHEADER *) &gen_bmi, (char*)in,(BITMAPINFOHEADER *) &gen_bmo, (char*)vidbufdec+sizeof(YV12_PLANES)))
|
||||
{
|
||||
//*is_kf=!(!in_len || ((unsigned char *)in)[0] > 0x7f);
|
||||
*is_kf=1;
|
||||
|
||||
if (need_kf && !*is_kf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
YV12_PLANES *image_vbd=(YV12_PLANES *)vidbufdec;
|
||||
image_vbd->y.baseAddr=(unsigned char *)(image_vbd+1);
|
||||
image_vbd->v.baseAddr=((unsigned char *)(image_vbd+1)) + width*height;
|
||||
image_vbd->u.baseAddr=((unsigned char *)(image_vbd+1)) + width*height*5/4;
|
||||
image_vbd->y.rowBytes=width;
|
||||
image_vbd->v.rowBytes=width/2;
|
||||
image_vbd->u.rowBytes=width/2;
|
||||
*out=(void*)vidbufdec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static IVideoDecoder *createVfw(int w, int h, double framerate, unsigned int type, int *flip)
|
||||
{
|
||||
HIC gen_hic = ICOpen(ICTYPE_VIDEO, type, ICMODE_DECOMPRESS);
|
||||
|
||||
if (!gen_hic) return 0;
|
||||
|
||||
BITMAPINFO gen_bmo={0,},gen_bmi={0,};
|
||||
gen_bmi.bmiHeader.biSize=sizeof(gen_bmi.bmiHeader);
|
||||
gen_bmi.bmiHeader.biCompression = type;
|
||||
gen_bmi.bmiHeader.biHeight=h;
|
||||
gen_bmi.bmiHeader.biWidth =w;
|
||||
gen_bmi.bmiHeader.biPlanes=1;
|
||||
|
||||
gen_bmo.bmiHeader.biSize=sizeof(gen_bmo.bmiHeader);
|
||||
gen_bmo.bmiHeader.biCompression = mmioFOURCC('Y','V','1','2');
|
||||
gen_bmo.bmiHeader.biHeight=h;
|
||||
gen_bmo.bmiHeader.biWidth =w;
|
||||
gen_bmo.bmiHeader.biSizeImage=(w*h*3)/2;
|
||||
gen_bmo.bmiHeader.biPlanes=1;
|
||||
gen_bmo.bmiHeader.biBitCount=12;
|
||||
|
||||
|
||||
if (ICERR_OK !=ICDecompressBegin(gen_hic, &gen_bmi, &gen_bmo))
|
||||
{
|
||||
ICClose(gen_hic);
|
||||
return 0;
|
||||
}
|
||||
Gen_Decoder *t=new Gen_Decoder(w,h);
|
||||
t->gen_bmi=gen_bmi;
|
||||
t->gen_bmo=gen_bmo;
|
||||
t->gen_hic=gen_hic;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BUILTIN_DIVX_SUPPORT
|
||||
#include "../../divx5/decore.h"
|
||||
|
||||
class CrapDivxDecoder : public IVideoDecoder {
|
||||
public:
|
||||
CrapDivxDecoder(int w, int h)
|
||||
{
|
||||
predict_keyframes=1;
|
||||
divx_param.x_dim = w;
|
||||
divx_param.y_dim = h;
|
||||
divx_param.output_format = DEC_USER;
|
||||
divx_param.codec_version = 412; // indicates that the stream is DivX 4.12 compatible
|
||||
divx_param.build_number = 0; // in this case, the build field is ignored
|
||||
divx_param.time_incr = 15; // time_incr default value
|
||||
|
||||
g_decore((long) this, DEC_OPT_MEMORY_REQS, &divx_param, &decMemReqs);
|
||||
|
||||
// the application allocates the data structures and the buffers
|
||||
divx_param.buffers.mp4_edged_ref_buffers = malloc(decMemReqs.mp4_edged_ref_buffers_size);
|
||||
divx_param.buffers.mp4_edged_for_buffers = malloc(decMemReqs.mp4_edged_for_buffers_size);
|
||||
divx_param.buffers.mp4_edged_back_buffers = malloc(decMemReqs.mp4_edged_back_buffers_size);
|
||||
divx_param.buffers.mp4_display_buffers = malloc(decMemReqs.mp4_display_buffers_size);
|
||||
divx_param.buffers.mp4_state = malloc(decMemReqs.mp4_state_size);
|
||||
divx_param.buffers.mp4_tables = malloc(decMemReqs.mp4_tables_size);
|
||||
divx_param.buffers.mp4_stream = malloc(decMemReqs.mp4_stream_size);
|
||||
divx_param.buffers.mp4_reference = malloc(decMemReqs.mp4_reference_size);
|
||||
|
||||
memset(divx_param.buffers.mp4_state, 0, decMemReqs.mp4_state_size);
|
||||
memset(divx_param.buffers.mp4_tables, 0, decMemReqs.mp4_tables_size);
|
||||
memset(divx_param.buffers.mp4_stream, 0, decMemReqs.mp4_stream_size);
|
||||
memset(divx_param.buffers.mp4_reference, 0, decMemReqs.mp4_reference_size);
|
||||
|
||||
g_decore((long) this, DEC_OPT_INIT, &divx_param, NULL);
|
||||
}
|
||||
~CrapDivxDecoder()
|
||||
{
|
||||
if (g_decore)
|
||||
{
|
||||
g_decore((long) this,DEC_OPT_RELEASE,NULL,NULL);
|
||||
free(divx_param.buffers.mp4_display_buffers);
|
||||
free(divx_param.buffers.mp4_edged_for_buffers);
|
||||
free(divx_param.buffers.mp4_edged_back_buffers);
|
||||
free(divx_param.buffers.mp4_edged_ref_buffers);
|
||||
free(divx_param.buffers.mp4_reference);
|
||||
free(divx_param.buffers.mp4_state);
|
||||
free(divx_param.buffers.mp4_stream);
|
||||
free(divx_param.buffers.mp4_tables);
|
||||
}
|
||||
if (!--divx_cnt)
|
||||
{
|
||||
FreeModule(hDivxLib);
|
||||
hDivxLib=0;
|
||||
g_decore=0;
|
||||
}
|
||||
}
|
||||
int decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf)
|
||||
{
|
||||
*out_type=NSV_MAKETYPE('Y','V','1','2');
|
||||
*out=NULL;
|
||||
int kfpredict=0;
|
||||
if (predict_keyframes && in_len>3)
|
||||
{
|
||||
kfpredict=!((unsigned char *)in)[3];
|
||||
if (need_kf && !kfpredict) return 0;
|
||||
}
|
||||
if (!in_len) return 0;
|
||||
*is_kf=kfpredict;
|
||||
|
||||
DEC_PICTURE pic;
|
||||
DEC_FRAME decFrame;
|
||||
|
||||
decFrame.bitstream = in;
|
||||
decFrame.bmp = &pic;
|
||||
decFrame.length = in_len;
|
||||
decFrame.render_flag = 1;
|
||||
|
||||
DEC_FRAME_INFO fi;
|
||||
|
||||
if (g_decore((long) this, DEC_OPT_FRAME, &decFrame, &fi) == DEC_OK)
|
||||
{
|
||||
if (!kfpredict != !fi.intra) predict_keyframes=0;
|
||||
*is_kf=fi.intra;
|
||||
if (need_kf && !fi.intra) return 0;
|
||||
|
||||
image_vbd.y.baseAddr=(unsigned char *)pic.y;
|
||||
image_vbd.u.baseAddr=(unsigned char *)pic.u;
|
||||
image_vbd.v.baseAddr=(unsigned char *)pic.v;
|
||||
image_vbd.y.rowBytes=pic.stride_y;
|
||||
image_vbd.u.rowBytes=pic.stride_uv;
|
||||
image_vbd.v.rowBytes=pic.stride_uv;
|
||||
|
||||
*out=&image_vbd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void flush() { }
|
||||
|
||||
|
||||
static int (STDCALL *g_decore)(
|
||||
unsigned long handle, // handle - the handle of the calling entity, must be unique
|
||||
unsigned long dec_opt, // dec_opt - the option for docoding, see below
|
||||
void *param1, // param1 - the parameter 1 (it's actually meaning depends on dec_opt
|
||||
void *param2); // param2 - the parameter 2 (it's actually meaning depends on dec_opt
|
||||
static HINSTANCE hDivxLib;
|
||||
static int divx_cnt;
|
||||
|
||||
private:
|
||||
DEC_PARAM divx_param;
|
||||
YV12_PLANES image_vbd;
|
||||
DEC_MEM_REQS decMemReqs;
|
||||
int predict_keyframes;
|
||||
};
|
||||
|
||||
int (STDCALL *CrapDivxDecoder::g_decore)(
|
||||
unsigned long handle, // handle - the handle of the calling entity, must be unique
|
||||
unsigned long dec_opt, // dec_opt - the option for docoding, see below
|
||||
void *param1, // param1 - the parameter 1 (it's actually meaning depends on dec_opt
|
||||
void *param2)=0; // param2 - the parameter 2 (it's actually meaning depends on dec_opt
|
||||
HINSTANCE CrapDivxDecoder::hDivxLib=0;
|
||||
int CrapDivxDecoder::divx_cnt=0;
|
||||
|
||||
IVideoDecoder *DIVX_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip)
|
||||
{
|
||||
if (fmt == NSV_MAKETYPE('D','i','v','X'))
|
||||
{
|
||||
if (!CrapDivxDecoder::divx_cnt)
|
||||
{
|
||||
CrapDivxDecoder::hDivxLib=LoadLibrary("divx.dll");
|
||||
if (CrapDivxDecoder::hDivxLib) *((void**)&CrapDivxDecoder::g_decore)=GetProcAddress(CrapDivxDecoder::hDivxLib,"decore");
|
||||
}
|
||||
CrapDivxDecoder::divx_cnt++;
|
||||
if (CrapDivxDecoder::g_decore) return new CrapDivxDecoder(w,h);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // end of divx gayness
|
||||
|
||||
class NullVideoDecoder : public IVideoDecoder
|
||||
{
|
||||
public:
|
||||
NullVideoDecoder() { }
|
||||
~NullVideoDecoder() { }
|
||||
int decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf)
|
||||
{
|
||||
*out_type=NSV_MAKETYPE('Y','V','1','2');
|
||||
*is_kf=1;
|
||||
*out=NULL;
|
||||
return 0;
|
||||
}
|
||||
void flush() { }
|
||||
};
|
||||
|
||||
|
||||
class NullAudioDecoder : public IAudioDecoder
|
||||
{
|
||||
public:
|
||||
NullAudioDecoder(){}
|
||||
~NullAudioDecoder(){}
|
||||
int decode(void *in, int in_len,
|
||||
void *out, int *out_len,
|
||||
unsigned int out_fmt[8])
|
||||
{
|
||||
*out_len=0;
|
||||
out_fmt[0]=NSV_MAKETYPE('N','O','N','E'); // no output
|
||||
return 0;
|
||||
}
|
||||
void flush(){}
|
||||
};
|
||||
|
||||
#ifdef BUILTIN_PCM_SUPPORT
|
||||
class PCMAudioDecoder : public IAudioDecoder
|
||||
{
|
||||
public:
|
||||
PCMAudioDecoder() { fused=4; }
|
||||
~PCMAudioDecoder(){}
|
||||
int decode(void *in, int in_len,
|
||||
void *out, int *out_len,
|
||||
unsigned int out_fmt[8])
|
||||
{
|
||||
if (in_len < 4)
|
||||
{
|
||||
*out_len=0;
|
||||
out_fmt[0]=0;
|
||||
return 0; // screw this frame
|
||||
}
|
||||
unsigned char *t=(unsigned char *)in;
|
||||
int bps=t[0];
|
||||
int nch=t[1];
|
||||
int srate=((int)t[2] | (((int)t[3])<<8));
|
||||
|
||||
out_fmt[0]=NSV_MAKETYPE('P','C','M',' ');
|
||||
out_fmt[1]=srate;
|
||||
out_fmt[2]=nch;
|
||||
out_fmt[3]=bps;
|
||||
|
||||
int l=in_len-fused;
|
||||
if (l > *out_len) l = *out_len;
|
||||
l&=~(nch*(bps/8)-1);
|
||||
|
||||
if (l) memcpy(out,(char *)in + fused,l);
|
||||
fused+=l;
|
||||
*out_len=l;
|
||||
|
||||
if (fused >= in_len)
|
||||
{
|
||||
fused=4;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
void flush() { fused=4; }
|
||||
private:
|
||||
int fused;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef DLL_DECODER_SUPPORT
|
||||
static char DLL_Dir[MAX_PATH];
|
||||
static HINSTANCE DLL_Handles[512];
|
||||
#endif
|
||||
|
||||
|
||||
void Decoders_Init(char *wapluginspath)
|
||||
{
|
||||
#ifdef DLL_DECODER_SUPPORT
|
||||
HKEY hKey;
|
||||
|
||||
if (!DLL_Dir[0] && RegOpenKeyExA(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion",
|
||||
0,KEY_READ,&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD l = sizeof(DLL_Dir);
|
||||
DWORD t;
|
||||
if (RegQueryValueExA(hKey,"CommonFilesDir",NULL,&t,(LPBYTE)DLL_Dir,&l ) != ERROR_SUCCESS || t != REG_SZ) DLL_Dir[0]=0;
|
||||
DLL_Dir[sizeof(DLL_Dir)-5]=0;
|
||||
CreateDirectoryA(DLL_Dir,NULL);
|
||||
strcat(DLL_Dir,"\\NSV");
|
||||
CreateDirectoryA(DLL_Dir,NULL);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
if (!DLL_Dir[0]) GetTempPathA(sizeof(DLL_Dir),DLL_Dir);
|
||||
Decoders_Quit();
|
||||
|
||||
HANDLE h;
|
||||
int x=0;
|
||||
WIN32_FIND_DATAA fd = {0};
|
||||
char buf[MAX_PATH*2+1] = {0};
|
||||
|
||||
#ifndef DLL_DECODER_SUPPORT_NOCURDIR
|
||||
char curdir[MAX_PATH] = {0};
|
||||
|
||||
strcpy( curdir, ".\\" );
|
||||
|
||||
strcpy( buf, curdir );
|
||||
strcat( buf, "nsvdec_*.dll" );
|
||||
|
||||
OutputDebugString( buf ); OutputDebugString( "\n" );
|
||||
|
||||
h = FindFirstFile(buf,&fd);
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
strcpy(buf,curdir);
|
||||
strcat(buf,fd.cFileName);
|
||||
|
||||
DLL_Handles[x]=LoadLibrary(buf);
|
||||
if (DLL_Handles[x])
|
||||
{
|
||||
if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") ||
|
||||
GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++;
|
||||
else
|
||||
{
|
||||
FreeLibrary(DLL_Handles[x]);
|
||||
DLL_Handles[x]=0;
|
||||
}
|
||||
}
|
||||
} while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFile(h,&fd));
|
||||
FindClose(h);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DLL_DECODER_SUPPORT_IN_
|
||||
|
||||
if (wapluginspath && wapluginspath[0])
|
||||
{
|
||||
lstrcpynA(buf,wapluginspath,sizeof(buf)-16);
|
||||
strcat(buf,"\\in_*.dll");
|
||||
h = FindFirstFileA(buf,&fd);
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
strncpy(buf, wapluginspath, MAX_PATH);
|
||||
strncat(buf, "\\", MAX_PATH);
|
||||
strncat(buf, fd.cFileName, MAX_PATH);
|
||||
|
||||
DLL_Handles[x]=LoadLibraryA(buf);
|
||||
if (DLL_Handles[x])
|
||||
{
|
||||
if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") ||
|
||||
GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++;
|
||||
else
|
||||
{
|
||||
FreeLibrary(DLL_Handles[x]);
|
||||
DLL_Handles[x]=0;
|
||||
}
|
||||
}
|
||||
} while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFileA(h,&fd));
|
||||
FindClose(h);
|
||||
}
|
||||
lstrcpynA(buf,wapluginspath,sizeof(buf)-16);
|
||||
strcat(buf,"\\nsvdec_*.dll");
|
||||
h = FindFirstFileA(buf,&fd);
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
strncpy(buf, wapluginspath, MAX_PATH);
|
||||
strncat(buf, "\\", MAX_PATH);
|
||||
strncat(buf, fd.cFileName, MAX_PATH);
|
||||
|
||||
DLL_Handles[x]=LoadLibraryA(buf);
|
||||
if (DLL_Handles[x])
|
||||
{
|
||||
if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") ||
|
||||
GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++;
|
||||
else
|
||||
{
|
||||
FreeLibrary(DLL_Handles[x]);
|
||||
DLL_Handles[x]=0;
|
||||
}
|
||||
}
|
||||
} while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFileA(h,&fd));
|
||||
FindClose(h);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WINAMPX
|
||||
strncpy(buf, DLL_Dir, MAX_PATH);
|
||||
strncat(buf, "\\nsvdec_*.dll", MAX_PATH);
|
||||
h = FindFirstFileA(buf,&fd);
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
strncpy(buf, DLL_Dir, MAX_PATH);
|
||||
strncat(buf, "\\", MAX_PATH);
|
||||
strncat(buf, fd.cFileName, MAX_PATH);
|
||||
|
||||
DLL_Handles[x]=LoadLibraryA(buf);
|
||||
if (DLL_Handles[x])
|
||||
{
|
||||
if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") ||
|
||||
GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++;
|
||||
else
|
||||
{
|
||||
FreeLibrary(DLL_Handles[x]);
|
||||
DLL_Handles[x]=0;
|
||||
}
|
||||
}
|
||||
} while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFileA(h,&fd));
|
||||
FindClose(h);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Decoders_Quit()
|
||||
{
|
||||
#ifdef DLL_DECODER_SUPPORT
|
||||
int x;
|
||||
for (x = 0; x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && DLL_Handles[x]; x ++)
|
||||
{
|
||||
FreeLibrary(DLL_Handles[x]);
|
||||
DLL_Handles[x]=0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static IAudioDecoder *CreateAudioDecoderWasabi(unsigned int type, IAudioOutput **output)
|
||||
{
|
||||
int n = 0;
|
||||
waServiceFactory *sf = 0;
|
||||
while (sf = mod.service->service_enumService(WaSvc::NSVFACTORY, n++))
|
||||
{
|
||||
svc_nsvFactory *factory = (svc_nsvFactory *)sf->getInterface();
|
||||
if (factory)
|
||||
{
|
||||
IAudioDecoder *decoder = factory->CreateAudioDecoder(type, output);
|
||||
sf->releaseInterface(factory);
|
||||
if (decoder)
|
||||
return decoder;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static IVideoDecoder *CreateVideoDecoderWasabi(int w, int h, double framerate, unsigned int type, int *flip)
|
||||
{
|
||||
int n=0;
|
||||
waServiceFactory *sf = 0;
|
||||
while (sf = mod.service->service_enumService(WaSvc::NSVFACTORY, n++))
|
||||
{
|
||||
svc_nsvFactory *factory = (svc_nsvFactory *)sf->getInterface();
|
||||
if (factory)
|
||||
{
|
||||
IVideoDecoder *decoder = factory->CreateVideoDecoder(w, h, framerate, type, flip);
|
||||
sf->releaseInterface(factory);
|
||||
if (decoder)
|
||||
return decoder;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
IAudioDecoder *CreateAudioDecoder(unsigned int type, int *wasNotNull, IAudioOutput **output)
|
||||
{
|
||||
IAudioDecoder *a=NULL;
|
||||
if (mod.service && !a)
|
||||
a = CreateAudioDecoderWasabi(type, output);
|
||||
#ifdef BUILTIN_MP3_SUPPORT
|
||||
if (!a) a=MP3_CREATE(type);
|
||||
#endif
|
||||
#ifdef BUILTIN_PCM_SUPPORT
|
||||
if (!a && type == NSV_MAKETYPE('P','C','M',' ')) a=new PCMAudioDecoder;
|
||||
#endif
|
||||
#ifdef BUILTIN_AAC_SUPPORT
|
||||
extern IAudioDecoder *AAC_CREATE(unsigned int fmt, IAudioOutput **output);
|
||||
if (!a && (type == NSV_MAKETYPE('A','A','C',' ') || type == NSV_MAKETYPE('V','L','B',' '))) a=AAC_CREATE(type,NULL);
|
||||
#endif
|
||||
#ifdef BUILTIN_AACP_SUPPOT
|
||||
extern IAudioDecoder *AACP_CREATE(unsigned int fmt, IAudioOutput **output);
|
||||
if (!a && (type == NSV_MAKETYPE('A','A','C','P') || type == NSV_MAKETYPE('A','A','C',' '))) a=AAC_CREATE(type,NULL);
|
||||
#endif
|
||||
#ifdef DLL_DECODER_SUPPORT
|
||||
int x;
|
||||
for (x = 0; !a && x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && DLL_Handles[x]; x ++)
|
||||
{
|
||||
IAudioDecoder *(*cad)(unsigned int type, IAudioOutput **output);
|
||||
*((void**)&cad) = (void*)GetProcAddress(DLL_Handles[x],"CreateAudioDecoder");
|
||||
if (cad) a=cad(type,output);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!a)
|
||||
{
|
||||
*wasNotNull=0;
|
||||
void *mem = WASABI_API_MEMMGR->sysMalloc(sizeof(NullAudioDecoder));
|
||||
a = new (mem) NullAudioDecoder();
|
||||
}
|
||||
else *wasNotNull=1;
|
||||
return a;
|
||||
}
|
||||
|
||||
IVideoDecoder *CreateVideoDecoder(int w, int h, double framerate, unsigned int type, int *flip, int *wasNotNull)
|
||||
{
|
||||
IVideoDecoder *v=NULL;
|
||||
if (mod.service && !v)
|
||||
v = CreateVideoDecoderWasabi(w, h, framerate, type, flip);
|
||||
#ifdef BUILTIN_DIVX_SUPPORT
|
||||
if (!v) v=DIVX_CREATE(w,h,framerate,type,flip);
|
||||
#endif
|
||||
#ifdef BUILTIN_VP3_SUPPORT
|
||||
if (!v) v=VP3_CREATE(w,h,framerate,type,flip);
|
||||
#endif
|
||||
#ifdef BUILTIN_VP5_SUPPORT
|
||||
if (!v) v=VP5_CREATE(w,h,framerate,type,flip);
|
||||
#endif
|
||||
#ifdef BUILTIN_VP6_SUPPORT
|
||||
extern IVideoDecoder *VP6_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip);
|
||||
if (!v) v=VP6_CREATE(w,h,framerate,type,flip);
|
||||
#endif
|
||||
#ifdef DLL_DECODER_SUPPORT
|
||||
int x;
|
||||
for (x = 0; !v && x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && DLL_Handles[x]; x ++)
|
||||
{
|
||||
IVideoDecoder *(*cvd)(int w, int h, double framerate, unsigned int type, int *flip);
|
||||
*((void**)&cvd) = (void*)GetProcAddress(DLL_Handles[x],"CreateVideoDecoder");
|
||||
if (cvd) v=cvd(w,h,framerate,type,flip);
|
||||
}
|
||||
#endif
|
||||
#ifdef BUILTIN_VFW_SUPPORT
|
||||
if (!v)
|
||||
{
|
||||
v=createVfw(w,h,framerate,type,flip);
|
||||
}
|
||||
#endif
|
||||
if (!v)
|
||||
{
|
||||
if (wasNotNull) *wasNotNull=0;
|
||||
void *mem = WASABI_API_MEMMGR->sysMalloc(sizeof(NullVideoDecoder));
|
||||
v = new (mem) NullVideoDecoder();
|
||||
}
|
||||
else if (wasNotNull) *wasNotNull=1;
|
||||
|
||||
return v;
|
||||
}
|
230
Src/nsv/nsvplay/main.cpp
Normal file
230
Src/nsv/nsvplay/main.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "video.h"
|
||||
#include "resource.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
VideoOutput *vidOut;
|
||||
NSVDecoder *decode;
|
||||
int quit;
|
||||
} parms;
|
||||
|
||||
HINSTANCE g_hInstance;
|
||||
int g_bitmap_id=IDB_BITMAP1;
|
||||
|
||||
//#define NO_ABOUT_EGG
|
||||
|
||||
extern long glCounterNSVf, glSyncFrameCount, glNonSyncFrameCount;
|
||||
|
||||
#define WNDMENU_CAPTION "NSVPlay/0.994"
|
||||
#include "about.h"
|
||||
#include "wndmenu.h"
|
||||
|
||||
DWORD WINAPI pooThread(LPVOID p)
|
||||
{
|
||||
parms *parm=(parms*)p;
|
||||
unsigned int last_title_check=0;
|
||||
|
||||
while (!parm->quit)
|
||||
{
|
||||
int r=parm->decode->run(&parm->quit);
|
||||
if (r < 0)
|
||||
{
|
||||
if (parm->decode->get_error()) MessageBox(parm->vidOut->getHwnd(),parm->decode->get_error(),"NSV Player Error",MB_OK|MB_ICONSTOP);
|
||||
break;
|
||||
}
|
||||
else if (!r)
|
||||
{
|
||||
if ((GetTickCount()-last_title_check) > 1000)
|
||||
{
|
||||
char *v=parm->decode->getTitle();
|
||||
char *buf=(char*)malloc((v?strlen(v):0)+128);
|
||||
int posms=parm->decode->getpos();
|
||||
int lenms=parm->decode->getlen();
|
||||
char *s=parm->decode->getStatus();
|
||||
if (lenms != ~0)
|
||||
wsprintf(buf,"%s [%d:%02d/%d:%02d] @ %dkbps %s%s%s- NSV Player",v?v:"",
|
||||
posms/60000,(posms/1000)%60,
|
||||
lenms/60000,(lenms/1000)%60,
|
||||
parm->decode->getBitrate()/1000,
|
||||
s?"[":"",s?s:"",s?"] ":""
|
||||
);
|
||||
else
|
||||
wsprintf(buf,"%s [%d:%02d] @ %dkbps %s%s%s- NSV Player",v?v:"",
|
||||
posms/60000,(posms/1000)%60,
|
||||
parm->decode->getBitrate()/1000,
|
||||
s?"[":"",s?s:"",s?"] ":""
|
||||
);
|
||||
|
||||
char *p=buf;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '_') *p=' ';
|
||||
p++;
|
||||
}
|
||||
|
||||
SetWindowText(parm->vidOut->getHwnd(),buf);
|
||||
free(buf);
|
||||
|
||||
last_title_check=GetTickCount();
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
parm->quit++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int g_quit;
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmdParam, int nCmdShow)
|
||||
{
|
||||
g_hInstance=hInstance;
|
||||
|
||||
BOOL bDisplayInfoAtEnd = FALSE;
|
||||
char *subtitlefile=NULL;
|
||||
char buf[11];
|
||||
lstrcpyn(buf,lpszCmdParam,11);
|
||||
|
||||
if(strstr(lpszCmdParam, "/info")) {
|
||||
bDisplayInfoAtEnd = TRUE;
|
||||
}
|
||||
|
||||
if (!lstrcmpi(buf,"/subtitle="))
|
||||
{
|
||||
lpszCmdParam += 10;
|
||||
char scanc=' ';
|
||||
if (*lpszCmdParam == '\"')
|
||||
{
|
||||
scanc=*lpszCmdParam++;
|
||||
}
|
||||
subtitlefile=lpszCmdParam;
|
||||
while (*lpszCmdParam && *lpszCmdParam != scanc) lpszCmdParam++;
|
||||
*lpszCmdParam++=0;
|
||||
while (*lpszCmdParam == ' ') lpszCmdParam++;
|
||||
}
|
||||
|
||||
if (*lpszCmdParam == '\"')
|
||||
{
|
||||
lpszCmdParam++;
|
||||
char *p=strstr(lpszCmdParam,"\"");
|
||||
if (p) *p=0;
|
||||
}
|
||||
|
||||
if (!*lpszCmdParam)
|
||||
{
|
||||
MessageBox(NULL,"Usage: nsvplay.exe [/subtitle=\"file|url\"] filename.nsv|http://url.nsv","NSV Player",MB_OK|MB_ICONINFORMATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xpos=CW_USEDEFAULT;
|
||||
int ypos=CW_USEDEFAULT;
|
||||
|
||||
_ReadConfigItemInt("xpos",&xpos);
|
||||
_ReadConfigItemInt("ypos",&ypos);
|
||||
|
||||
VideoOutput *vidOut = new VideoOutput(NULL,xpos,ypos);
|
||||
Decoders_Init();
|
||||
|
||||
|
||||
NSVDecoder *decode=new NSVDecoder(lpszCmdParam,vidOut,subtitlefile);
|
||||
vidOut->setNSVDecoder(decode);
|
||||
|
||||
int m_pause=0;
|
||||
|
||||
|
||||
vidOut->vid_vsync=false;
|
||||
|
||||
|
||||
_ReadConfigItemInt("vsync",&vidOut->vid_vsync);
|
||||
_ReadConfigItemInt("overlays",&vidOut->vid_overlays);
|
||||
_ReadConfigItemInt("ddraw",&vidOut->vid_ddraw);
|
||||
_ReadConfigItemInt("aspectadj",&vidOut->vid_aspectadj);
|
||||
_ReadConfigItemInt("use_mixer",&g_audio_use_mixer);
|
||||
{
|
||||
int temp=1;
|
||||
_ReadConfigItemInt("subtitles",&temp);
|
||||
decode->enableSubs(temp);
|
||||
temp=0;
|
||||
_ReadConfigItemInt("subtitles_size",&temp);
|
||||
decode->setSubsFontSize(temp);
|
||||
}
|
||||
|
||||
DWORD id;
|
||||
parms parm={0,};
|
||||
parm.decode=decode;
|
||||
parm.vidOut=vidOut;
|
||||
|
||||
vidOut->setcallback(my_wndcallback,&parm);
|
||||
|
||||
HANDLE hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)pooThread,(LPVOID)&parm,0,&id);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
|
||||
{
|
||||
if (msg.hwnd == vidOut->getHwnd() && msg.message == WM_KEYDOWN)
|
||||
{
|
||||
if (msg.wParam == VK_SPACE) decode->pause(m_pause=!m_pause);
|
||||
if (msg.wParam == VK_LEFT) decode->seek(decode->getpos()-30000);
|
||||
if (msg.wParam == VK_RIGHT) decode->seek(decode->getpos()+30000);
|
||||
if (msg.wParam == VK_UP)
|
||||
{
|
||||
int vol=decode->getvolume()+16;
|
||||
if (vol > 255) vol=255;
|
||||
decode->setvolume(vol);
|
||||
}
|
||||
if (msg.wParam == VK_DOWN)
|
||||
{
|
||||
int vol=decode->getvolume()-16;
|
||||
if (vol < 0) vol=0;
|
||||
decode->setvolume(vol);
|
||||
}
|
||||
if (msg.wParam == VK_RETURN)
|
||||
{
|
||||
if (vidOut->is_fullscreen()) vidOut->remove_fullscreen();
|
||||
else vidOut->fullscreen();
|
||||
}
|
||||
if (msg.wParam == 'v' || msg.wParam == 'V')
|
||||
{
|
||||
vidOut->vid_vsync=!vidOut->vid_vsync;
|
||||
}
|
||||
if (msg.wParam == 'a' || msg.wParam == 'A')
|
||||
{
|
||||
vidOut->vid_aspectadj=!vidOut->vid_aspectadj;
|
||||
PostMessage(vidOut->getHwnd(),WM_TIMER,1,0);
|
||||
}
|
||||
}
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
if (!IsWindow(vidOut->getHwnd()) || parm.quit) break;
|
||||
|
||||
Sleep(50);
|
||||
|
||||
}
|
||||
parm.quit++;
|
||||
WaitForSingleObject(hThread,INFINITE);
|
||||
CloseHandle(hThread);
|
||||
delete decode;
|
||||
delete vidOut;
|
||||
|
||||
Decoders_Quit();
|
||||
|
||||
#if _DEBUG
|
||||
// if "/info" on the command line, display some statistics about the movie
|
||||
if(bDisplayInfoAtEnd) {
|
||||
char szMessage[MAX_PATH];
|
||||
|
||||
wsprintf(szMessage, "File Header Count=%ld\nSync Frames=%ld\nNon-sync Frames=%ld", glCounterNSVf, glSyncFrameCount, glNonSyncFrameCount);
|
||||
MessageBox(NULL, szMessage, WNDMENU_CAPTION, MB_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
248
Src/nsv/nsvplay/main.h
Normal file
248
Src/nsv/nsvplay/main.h
Normal file
@ -0,0 +1,248 @@
|
||||
#ifndef NSVPLAY_MAIN_H
|
||||
#define NSVPLAY_MAIN_H
|
||||
|
||||
#include <bfc/platform/types.h>
|
||||
#include "../nsvlib.h"
|
||||
#include "../dec_if.h"
|
||||
|
||||
#define SHOW_STREAM_TITLE_AT_TOP 1
|
||||
|
||||
class Subtitles;
|
||||
class SubsItem;
|
||||
|
||||
#include "IDataReader.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *language;
|
||||
const char *utf8_text;
|
||||
unsigned int start_frame, end_frame;
|
||||
unsigned char xPos, yPos;
|
||||
unsigned char colorRed, colorGreen, colorBlue;
|
||||
signed char fontSize;
|
||||
int extraDataSize;
|
||||
const void *extraData;
|
||||
} SUBTITLE_INFO;
|
||||
|
||||
class IVideoOutput
|
||||
{
|
||||
public:
|
||||
virtual ~IVideoOutput() { }
|
||||
virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0;
|
||||
#ifdef _WIN32
|
||||
virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { }
|
||||
#else
|
||||
virtual void setcallback(void *func, void *token) { } // currently unused, here to reserve the spot in the vtable
|
||||
#endif
|
||||
virtual void close()=0;
|
||||
virtual void draw(void *frame)=0;
|
||||
virtual void drawSubtitle(SubsItem *item) { }
|
||||
virtual void showStatusMsg(const char *text) { }
|
||||
virtual int get_latency() { return 0; }
|
||||
virtual void notifyBufferState(int bufferstate) { } /* 0-255*/
|
||||
|
||||
virtual intptr_t extended(intptr_t param1, intptr_t param2, intptr_t param3) { return 0; } // Dispatchable, eat this!
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class ClassList {
|
||||
public:
|
||||
~ClassList() {
|
||||
int l=getlen()-1;
|
||||
for(int i=l;i>-1;i--) delete(get(i));
|
||||
}
|
||||
void put(T *item) {
|
||||
m_buf.add(&item,sizeof(T *));
|
||||
}
|
||||
T *get(int n) {
|
||||
if(n>=getlen()) return NULL;
|
||||
return ((T **)m_buf.get())[n];
|
||||
}
|
||||
int getlen() {
|
||||
return (int)(m_buf.getlen()/sizeof(SubsItem *));
|
||||
}
|
||||
private:
|
||||
GrowBuf m_buf;
|
||||
};
|
||||
|
||||
class SubtitlesItem {
|
||||
public:
|
||||
SubtitlesItem(const char *language, Subtitles *subs) :
|
||||
m_subs(subs) {
|
||||
m_language=_strdup(language);
|
||||
m_subs=subs;
|
||||
}
|
||||
~SubtitlesItem() {
|
||||
free((void *)m_language);
|
||||
}
|
||||
const char *m_language;
|
||||
Subtitles *m_subs;
|
||||
};
|
||||
|
||||
class NSVDecoder {
|
||||
|
||||
public:
|
||||
|
||||
NSVDecoder(const char *url, IVideoOutput *output, char *subtitleurl=NULL);
|
||||
~NSVDecoder();
|
||||
|
||||
char *get_error();
|
||||
char *get_status();
|
||||
int run(int * volatile quit=NULL);
|
||||
|
||||
void pause(int pause);
|
||||
ULONGLONG getpos();
|
||||
unsigned int getpos_frames() { return framecnt; }
|
||||
unsigned int getlen(); // returns 0xFFFFFFFF on unknown
|
||||
|
||||
void setvolume(int volume) { m_volume=volume; if (aud_output) aud_output->setvolume(volume); }
|
||||
void setpan(int pan) { m_pan=pan; if (aud_output) aud_output->setpan(pan); }
|
||||
|
||||
int getvolume() { return m_volume; }
|
||||
int getpan() { return m_pan; }
|
||||
|
||||
int canseek();
|
||||
void seek(unsigned int newpos);
|
||||
|
||||
char *getFromMeta(char *name);
|
||||
char *getUrl() { return m_url; }
|
||||
const char *getServerHeader(char *name);
|
||||
|
||||
char *getTitle();
|
||||
char *getStatus();
|
||||
|
||||
void getAudioDesc(char *buf);
|
||||
void getVideoDesc(char *buf);
|
||||
|
||||
char *getAudioType() { return m_audio_type; }
|
||||
char *getVideoType() { return m_video_type; }
|
||||
unsigned int getFileSize(); // 0xFFFFFFFF if unknown
|
||||
int getBitrate();
|
||||
int getAudioBitrate();
|
||||
int getVideoBitrate();
|
||||
int getWidth() { return unpacket.getWidth(); }
|
||||
int getHeight() { return unpacket.getHeight(); }
|
||||
double getFrameRate() { return use_framerate_override?framerate_override:unpacket.getFrameRate(); }
|
||||
int getBufferPos() { if (m_prebuffer) return m_bufstate; return 256; } // 0-256
|
||||
|
||||
int subsEnabled() { return m_enable_subtitles; }
|
||||
void enableSubs(int e) {
|
||||
m_enable_subtitles=e;
|
||||
if(!e&&m_out) m_out->drawSubtitle(NULL);
|
||||
}
|
||||
int getSubsFontSize() { return m_subs_fontsize; }
|
||||
void setSubsFontSize(int s) {
|
||||
m_subs_fontsize=s;
|
||||
if(m_out) m_out->drawSubtitle(NULL); //will redraw current subtitle with new size
|
||||
}
|
||||
|
||||
void SetPreciseSeeking(int prec) { m_precise_seeking=prec; }
|
||||
void SetBuffering(int total_ms, int initial_ms, int after_underrun);
|
||||
void SetBufferMemoryLimit(int bytes) { m_buf_memlimit=bytes; }
|
||||
|
||||
const char *getSubLanguage(int index);
|
||||
void setSubLanguage(int index) { m_cur_subtitle=index; }
|
||||
int getCurSubLanguage() { return m_cur_subtitle; }
|
||||
|
||||
void CloseVideo()
|
||||
{
|
||||
if (m_out_opened)
|
||||
m_out->close();
|
||||
m_out_opened=0;
|
||||
}
|
||||
|
||||
private:
|
||||
ULONGLONG m_avresync_time;
|
||||
int m_pb_init,m_pb_init_ur,m_buffer_total;
|
||||
int m_prebuffer;
|
||||
int m_bufstate;
|
||||
|
||||
int proTimerStart;
|
||||
int proTimerEnd;
|
||||
float profiletime;
|
||||
float prostart;
|
||||
float proend;
|
||||
float timeref;
|
||||
|
||||
int m_again;
|
||||
|
||||
void ProcessSubtitleBlock(void *data, int len);
|
||||
|
||||
int m_paused;
|
||||
|
||||
ULONGLONG hack_l_curpos;
|
||||
ULONGLONG hack_l_curpos_ot;
|
||||
|
||||
int m_buf_memlimit;
|
||||
IVideoOutput *m_out;
|
||||
int m_out_opened;
|
||||
|
||||
nsv_InBS inbs;
|
||||
nsv_InBS audiobs,videobs;
|
||||
nsv_InBS auxbs;
|
||||
int video_frames_avail,audio_frames_avail;
|
||||
nsv_Unpacketer unpacket;
|
||||
unsigned int framecnt;
|
||||
int hdrsearched;
|
||||
int nsvbitstream_search;
|
||||
int64_t m_audio_writepos;
|
||||
unsigned int m_need_seek;
|
||||
|
||||
int seek_dumpframes, seek_dumpaudiosamples;
|
||||
int pcm_samplerate;
|
||||
|
||||
int m_precise_seeking;
|
||||
|
||||
char *m_err;
|
||||
char *m_url;
|
||||
char *m_title;
|
||||
|
||||
int vid_decoder_isnotnull,aud_decoder_isnotnull;
|
||||
IVideoDecoder *vid_decoder;
|
||||
IAudioDecoder *aud_decoder;
|
||||
IAudioOutput *aud_output;
|
||||
IDataReader *file_reader;
|
||||
int needkf;
|
||||
double aspect;
|
||||
double framerate_override;
|
||||
int use_framerate_override;
|
||||
|
||||
nsv_fileHeader fileheader;
|
||||
|
||||
unsigned int avg_framesize_cnt,avg_framesize_tot;
|
||||
unsigned int avg_framesize_cnt_v,avg_framesize_tot_v;
|
||||
unsigned int avg_framesize_cnt_a,avg_framesize_tot_a;
|
||||
|
||||
int vidout_ready;
|
||||
int vid_flip;
|
||||
void *vidout;
|
||||
unsigned int vidout_type;
|
||||
unsigned int vidout_time;
|
||||
unsigned int vidout_codec_width;
|
||||
unsigned int vidout_codec_height;
|
||||
|
||||
char m_audio_type[5];
|
||||
char m_video_type[5];
|
||||
|
||||
int m_volume, m_pan;
|
||||
|
||||
int m_enable_subtitles;
|
||||
int m_subs_fontsize;
|
||||
ClassList<SubtitlesItem> m_subtitles;
|
||||
int m_cur_subtitle;
|
||||
|
||||
Subtitles *insertSubtitlesItem(const char *language, const char *subfile);
|
||||
Subtitles *findSubtitles(const char *language);
|
||||
|
||||
};
|
||||
|
||||
void Decoders_Init(char *wapluginspath=NULL);
|
||||
void Decoders_Quit();
|
||||
|
||||
|
||||
IAudioDecoder *CreateAudioDecoder(unsigned int type, int *wasNotNull, IAudioOutput **output);
|
||||
IVideoDecoder *CreateVideoDecoder(int w, int h, double framerate, unsigned int type, int *flip, int *wasNotNull=NULL);
|
||||
IDataReader *CreateReader(const char *url);
|
||||
|
||||
#endif //NSVPLAY_MAIN_H
|
73
Src/nsv/nsvplay/mp3stub.cpp
Normal file
73
Src/nsv/nsvplay/mp3stub.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include "mp3stub.h"
|
||||
#include "../../mp3dec/mpgadecoder.h"
|
||||
|
||||
int mp3_quality;
|
||||
int mp3_downmix;
|
||||
|
||||
class MP3_Decoder : public IAudioDecoder
|
||||
{
|
||||
public:
|
||||
MP3_Decoder() : mp3_dec(mp3_quality,0,mp3_downmix) { fused=0; pcm_buf_used=0; }
|
||||
~MP3_Decoder() { };
|
||||
int decode(void *in, int in_len,
|
||||
void *out, int *out_len,
|
||||
unsigned int out_fmt[8]);
|
||||
void flush() { fused=0; pcm_buf_used=0; mp3_dec.Reset(); }
|
||||
private:
|
||||
CMpgaDecoder mp3_dec;
|
||||
char pcm_buf[1152*4*2];
|
||||
int pcm_buf_used;
|
||||
int pcm_offs;
|
||||
int fused;
|
||||
};
|
||||
|
||||
int MP3_Decoder::decode(void *in, int in_len,
|
||||
void *out, int *out_len,
|
||||
unsigned int out_fmt[8])
|
||||
{
|
||||
int rval=1;
|
||||
if (fused < in_len)
|
||||
{
|
||||
int l=mp3_dec.GetInputFree();
|
||||
if (l > in_len-fused) l=in_len-fused;
|
||||
if (l) mp3_dec.Fill((unsigned char *)in + fused,l);
|
||||
fused+=l;
|
||||
}
|
||||
|
||||
if (!pcm_buf_used)
|
||||
{
|
||||
SSC s=mp3_dec.DecodeFrame((unsigned char *)pcm_buf,sizeof(pcm_buf),&pcm_buf_used);
|
||||
pcm_offs=0;
|
||||
}
|
||||
|
||||
if (pcm_buf_used)
|
||||
{
|
||||
int l=*out_len;
|
||||
if (l > pcm_buf_used) l=pcm_buf_used;
|
||||
memcpy(out,pcm_buf+pcm_offs,l);
|
||||
pcm_buf_used-=l;
|
||||
pcm_offs+=l;
|
||||
*out_len=l;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fused >= in_len) rval=fused=0;
|
||||
*out_len=0;
|
||||
}
|
||||
|
||||
int nch=mp3_dec.m_Info.GetEffectiveChannels();
|
||||
int srate=mp3_dec.m_Info.GetEffectiveSFreq();
|
||||
out_fmt[0]=(nch && srate)?NSV_MAKETYPE('P','C','M',' '):0;
|
||||
out_fmt[1]=srate;
|
||||
out_fmt[2]=nch;
|
||||
out_fmt[3]=(nch && srate)?16:0;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
IAudioDecoder *MP3_CREATE(unsigned int fmt)
|
||||
{
|
||||
if (fmt == NSV_MAKETYPE('M','P','3',' ')) return new MP3_Decoder;
|
||||
return NULL;
|
||||
}
|
12
Src/nsv/nsvplay/mp3stub.h
Normal file
12
Src/nsv/nsvplay/mp3stub.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _MP3STUB_H_
|
||||
#define _MP3STUB_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
extern int mp3_quality;
|
||||
extern int mp3_downmix;
|
||||
extern int mp3_downshit;
|
||||
|
||||
IAudioDecoder *MP3_CREATE(unsigned int fmt);
|
||||
|
||||
#endif
|
BIN
Src/nsv/nsvplay/nsv_logo.bmp
Normal file
BIN
Src/nsv/nsvplay/nsv_logo.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
999
Src/nsv/nsvplay/nsvdecode.cpp
Normal file
999
Src/nsv/nsvplay/nsvdecode.cpp
Normal file
@ -0,0 +1,999 @@
|
||||
#include <bfc/platform/platform.h>
|
||||
#include <bfc/platform/strcmp.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include "audiostub.h"
|
||||
#include "api.h"
|
||||
#include "main.h"
|
||||
#include "subtitles.h"
|
||||
#include "../in_nsv/resource.h"
|
||||
|
||||
extern int config_subtitles;
|
||||
#ifdef __APPLE__
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
uint32_t GetTickCount()
|
||||
{
|
||||
struct timeval newtime;
|
||||
|
||||
gettimeofday(&newtime, 0);
|
||||
return newtime.tv_sec*1000 + newtime.tv_usec/1000;
|
||||
}
|
||||
|
||||
int MulDiv(int a, int b, int d)
|
||||
{
|
||||
return int ((int64_t)a * (int64_t)b) / (int64_t)d;
|
||||
}
|
||||
#endif
|
||||
class NullAudioOutput : public IAudioOutput
|
||||
{
|
||||
public:
|
||||
NullAudioOutput() { m_pause=0; m_pause_t=0; m_start_t=GetTickCount64(); }
|
||||
~NullAudioOutput(){}
|
||||
int canwrite() { return m_pause ? 0 : 65536; } // returns bytes writeable
|
||||
void write(void *buf, int len) { }
|
||||
ULONGLONG getpos() { return m_pause?m_pause_t:(GetTickCount64()-m_start_t); }
|
||||
int isplaying(void) { return -1; }
|
||||
ULONGLONG getwritepos() { return getpos(); }
|
||||
void flush(unsigned int newtime)
|
||||
{
|
||||
if (m_pause) m_pause_t=newtime;
|
||||
else m_start_t = GetTickCount64()-newtime;
|
||||
}
|
||||
void pause(int pause)
|
||||
{
|
||||
if (pause && !m_pause)
|
||||
{
|
||||
m_pause_t=GetTickCount64()-m_start_t;
|
||||
m_pause=1;
|
||||
}
|
||||
else if (!pause && m_pause)
|
||||
{
|
||||
m_start_t = GetTickCount64()-m_pause_t;
|
||||
m_pause=0;
|
||||
m_pause_t=0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_pause;
|
||||
ULONGLONG m_pause_t;
|
||||
ULONGLONG m_start_t;
|
||||
};
|
||||
|
||||
void NSVDecoder::pause(int pause)
|
||||
{
|
||||
if (aud_output) aud_output->pause(pause);
|
||||
m_paused=pause;
|
||||
}
|
||||
|
||||
ULONGLONG NSVDecoder::getpos()
|
||||
{
|
||||
return aud_output ? aud_output->getpos() : 0;
|
||||
}
|
||||
|
||||
unsigned int NSVDecoder::getlen()
|
||||
{
|
||||
if (!fileheader.header_size || fileheader.file_lenms == 0xFFFFFFFF)
|
||||
{
|
||||
if (!file_reader || !avg_framesize_cnt || !avg_framesize_tot) return 0xFFFFFFFF;
|
||||
int s=(int)file_reader->getsize();
|
||||
if (s == 0xFFFFFFFF) return 0xFFFFFFFF;
|
||||
|
||||
int bytespersec=(int)((double)avg_framesize_tot/(double)avg_framesize_cnt*getFrameRate());
|
||||
|
||||
if (!bytespersec) return 0xFFFFFFFF;
|
||||
return MulDiv(s,1000,bytespersec);
|
||||
}
|
||||
return fileheader.file_lenms;
|
||||
}
|
||||
|
||||
void NSVDecoder::seek(unsigned int newpos)
|
||||
{
|
||||
m_need_seek=newpos;
|
||||
m_again=0;
|
||||
}
|
||||
|
||||
int NSVDecoder::canseek()
|
||||
{
|
||||
return file_reader ? file_reader->canseek() : 0;
|
||||
}
|
||||
|
||||
char *NSVDecoder::getStatus()
|
||||
{
|
||||
if (m_prebuffer) return "Buffering";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NSVDecoder::SetBuffering(int total_ms, int initial_ms, int after_underrun)
|
||||
{
|
||||
if (m_prebuffer) m_prebuffer=initial_ms;
|
||||
m_pb_init=initial_ms;
|
||||
m_pb_init_ur=after_underrun;
|
||||
m_buffer_total=total_ms;
|
||||
}
|
||||
|
||||
|
||||
int64_t pdReadResolution(void)
|
||||
{
|
||||
int64_t myfeq;
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER feq;
|
||||
|
||||
QueryPerformanceFrequency( &feq);
|
||||
myfeq = feq.QuadPart;
|
||||
#else
|
||||
myfeq = 1000000;
|
||||
#endif
|
||||
|
||||
return myfeq;
|
||||
}
|
||||
|
||||
int64_t pdReadTimer(void)
|
||||
{
|
||||
int64_t mynow;
|
||||
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER now;
|
||||
|
||||
QueryPerformanceCounter( &now );
|
||||
mynow = now.QuadPart;
|
||||
#else
|
||||
struct timeval newtime;
|
||||
|
||||
gettimeofday(&newtime,NULL);
|
||||
mynow = (newtime.tv_sec * 1000000) + newtime.tv_usec ;
|
||||
#endif
|
||||
|
||||
return mynow;
|
||||
}
|
||||
|
||||
NSVDecoder::NSVDecoder(const char *url, IVideoOutput *output, char *subtitleurl)
|
||||
{
|
||||
m_precise_seeking=1;
|
||||
pcm_samplerate=0;
|
||||
seek_dumpframes=0;
|
||||
seek_dumpaudiosamples=0;
|
||||
m_avresync_time=0;
|
||||
nsvbitstream_search=0;
|
||||
m_paused=0;
|
||||
m_bufstate=0;
|
||||
hack_l_curpos=-1;
|
||||
hack_l_curpos_ot=0;
|
||||
vid_decoder_isnotnull=1;
|
||||
aud_decoder_isnotnull=1;
|
||||
video_frames_avail=0;
|
||||
audio_frames_avail=0;
|
||||
m_buffer_total=1000; // bufferahead
|
||||
m_pb_init=m_prebuffer=1500; // initial prebuffer
|
||||
m_pb_init_ur=1500; // after underrun
|
||||
m_buf_memlimit=32*1024*1024;
|
||||
m_pan=0;
|
||||
m_volume=192;
|
||||
m_title=0;
|
||||
m_audio_type[0]=m_video_type[0]=0;
|
||||
m_out_opened=0;
|
||||
m_out=output;
|
||||
vidout_ready=0;
|
||||
vidout=0;
|
||||
vidout_type=0;
|
||||
vidout_time=0;
|
||||
vidout_codec_width=0;
|
||||
vidout_codec_height=0;
|
||||
m_url=_strdup(url);
|
||||
m_need_seek=~0;
|
||||
needkf=1;
|
||||
aspect=1.0;
|
||||
framerate_override=0.0;
|
||||
use_framerate_override=0;
|
||||
vid_decoder=NULL;
|
||||
aud_decoder=NULL;
|
||||
aud_output=NULL;
|
||||
framecnt=0;
|
||||
hdrsearched=0;
|
||||
file_reader=CreateReader(url);
|
||||
if (!file_reader) m_err="Error opening input";
|
||||
else m_err=NULL;
|
||||
|
||||
m_enable_subtitles=1;
|
||||
m_subs_fontsize=0;
|
||||
m_cur_subtitle=0;
|
||||
if (subtitleurl && *subtitleurl) insertSubtitlesItem("From subtitle file",subtitleurl);
|
||||
|
||||
memset(&fileheader,0,sizeof(fileheader));
|
||||
|
||||
avg_framesize_tot=0;
|
||||
avg_framesize_cnt=0;
|
||||
avg_framesize_tot_v=0;
|
||||
avg_framesize_cnt_v=0;
|
||||
avg_framesize_tot_a=0;
|
||||
avg_framesize_cnt_a=0;
|
||||
|
||||
unpacket.setAudioOut(&audiobs);
|
||||
unpacket.setVideoOut(&videobs);
|
||||
unpacket.setAuxOut(&auxbs);
|
||||
|
||||
proTimerStart = 1;
|
||||
proTimerEnd = 0;
|
||||
profiletime = 0.00;
|
||||
prostart = 0.00;
|
||||
proend = 0.00;
|
||||
timeref = (float)pdReadResolution();
|
||||
|
||||
|
||||
m_again = 0;
|
||||
}
|
||||
|
||||
NSVDecoder::~NSVDecoder()
|
||||
{
|
||||
if (m_out_opened) m_out->close();
|
||||
if (WASABI_API_MEMMGR)
|
||||
WASABI_API_MEMMGR->Delete(vid_decoder);
|
||||
else
|
||||
delete vid_decoder;
|
||||
if (WASABI_API_MEMMGR)
|
||||
WASABI_API_MEMMGR->Delete(aud_decoder);
|
||||
else
|
||||
delete aud_decoder;
|
||||
delete aud_output;
|
||||
delete file_reader;
|
||||
free(fileheader.metadata);
|
||||
free(fileheader.toc);
|
||||
free(m_url);
|
||||
free(m_title);
|
||||
}
|
||||
|
||||
char *NSVDecoder::get_error()
|
||||
{
|
||||
return m_err;
|
||||
}
|
||||
|
||||
char *NSVDecoder::get_status()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *NSVDecoder::getFromMeta(char *name)
|
||||
{
|
||||
if (file_reader)
|
||||
{
|
||||
char *t=(char*)malloc(strlen(name)+8);
|
||||
if (t)
|
||||
{
|
||||
strcpy(t,"x-nsv-");
|
||||
strcat(t,name);
|
||||
char *v=file_reader->getheader(t);
|
||||
free(t);
|
||||
if (v) return _strdup(v);
|
||||
}
|
||||
}
|
||||
return nsv_getmetadata(fileheader.metadata,name);
|
||||
}
|
||||
|
||||
|
||||
unsigned int NSVDecoder::getFileSize()
|
||||
{
|
||||
if (file_reader) return (unsigned int)file_reader->getsize();
|
||||
return ~0;
|
||||
}
|
||||
|
||||
int NSVDecoder::getBitrate()
|
||||
{
|
||||
if (!fileheader.header_size || !fileheader.file_lenms || !fileheader.file_lenbytes ||
|
||||
fileheader.file_lenms == 0xFFFFFFFF || fileheader.file_lenbytes == 0xFFFFFFFF)
|
||||
{
|
||||
if (!avg_framesize_cnt) return 0;
|
||||
return (int) (8.0 * getFrameRate() * (double)avg_framesize_tot / (double)avg_framesize_cnt);
|
||||
}
|
||||
return MulDiv(fileheader.file_lenbytes,8000,fileheader.file_lenms);
|
||||
}
|
||||
|
||||
const char *NSVDecoder::getServerHeader(char *name)
|
||||
{
|
||||
return file_reader?file_reader->getheader(name):NULL;
|
||||
}
|
||||
|
||||
void NSVDecoder::getAudioDesc(char *buf)
|
||||
{
|
||||
char *t=getAudioType();
|
||||
if (t && *t)
|
||||
{
|
||||
if (strcmp(t, "VLB")==0)
|
||||
sprintf(buf,"Dolby AAC "); // special case; make sure the user never sees "VLB" name
|
||||
else if (strcmp(t, "AACP")==0)
|
||||
sprintf(buf,"HE-AAC ");
|
||||
else if (strcmp(t, "AAC")==0)
|
||||
sprintf(buf,"AAC LC ");
|
||||
else
|
||||
sprintf(buf,"%s ",t);
|
||||
|
||||
char *p=buf+strlen(buf);
|
||||
if (aud_output) aud_output->getdescstr(p);
|
||||
if (!*p) *--p=0;
|
||||
|
||||
int a=(getAudioBitrate()+500)/1000;
|
||||
if (a) sprintf(buf+strlen(buf)," ~%d%s",a,WASABI_API_LNGSTRING(IDS_KBPS));
|
||||
}
|
||||
else *buf=0;
|
||||
}
|
||||
|
||||
void NSVDecoder::getVideoDesc(char *buf)
|
||||
{
|
||||
char *t=getVideoType();
|
||||
if (t && *t)
|
||||
{
|
||||
int fr=(int)(getFrameRate()*100.0);
|
||||
sprintf(buf,"%s %dx%d@%d.%02d%s",t,getWidth(),getHeight(),fr/100,fr%100,WASABI_API_LNGSTRING(IDS_FPS));
|
||||
|
||||
int a=(getVideoBitrate()+500)/1000;
|
||||
if (a) sprintf(buf+strlen(buf)," ~%d%s",a,WASABI_API_LNGSTRING(IDS_KBPS));
|
||||
}
|
||||
else *buf=0;
|
||||
}
|
||||
|
||||
|
||||
int NSVDecoder::getAudioBitrate()
|
||||
{
|
||||
if (!avg_framesize_cnt_a) return 0;
|
||||
return (int) (8.0 * getFrameRate() * (double)avg_framesize_tot_a / (double)avg_framesize_cnt_a);
|
||||
}
|
||||
|
||||
int NSVDecoder::getVideoBitrate()
|
||||
{
|
||||
if (!avg_framesize_cnt_v) return 0;
|
||||
return (int) (8.0 * getFrameRate() * (double)avg_framesize_tot_v / (double)avg_framesize_cnt_v);
|
||||
}
|
||||
|
||||
char *NSVDecoder::getTitle()
|
||||
{
|
||||
char *v=getFromMeta("TITLE");
|
||||
if (v)
|
||||
{
|
||||
if (!m_title || strcmp(v,m_title))
|
||||
{
|
||||
free(m_title);
|
||||
m_title=v;
|
||||
}
|
||||
else free(v);
|
||||
return m_title;
|
||||
}
|
||||
if (file_reader)
|
||||
{
|
||||
v=file_reader->gettitle();
|
||||
if (v) return v;
|
||||
}
|
||||
|
||||
if (!m_url) return "";
|
||||
|
||||
v=m_url+strlen(m_url);
|
||||
while (v >= m_url && *v != '/' && *v != '\\' && *v != '=') v--;
|
||||
return ++v;
|
||||
}
|
||||
|
||||
void NSVDecoder::ProcessSubtitleBlock(void *data, int len)
|
||||
{
|
||||
unsigned char *dataptr=(unsigned char *)data;
|
||||
while (len > 2)
|
||||
{
|
||||
int len_block=(dataptr[0] | ((unsigned short)dataptr[1] << 8));
|
||||
dataptr += 2;
|
||||
len -= 2;
|
||||
if (len_block > len) break;
|
||||
|
||||
SUBTITLE_INFO sti={0,};
|
||||
sti.language = (char *)dataptr;
|
||||
while (len_block > 0 && *dataptr)
|
||||
{
|
||||
dataptr++;
|
||||
len_block--;
|
||||
len--;
|
||||
}
|
||||
dataptr++;
|
||||
len_block--;
|
||||
len--;
|
||||
if (len_block < 1) break;
|
||||
sti.utf8_text = (char *)dataptr;
|
||||
while (len_block > 0 && *dataptr)
|
||||
{
|
||||
dataptr++;
|
||||
len_block--;
|
||||
len--;
|
||||
}
|
||||
dataptr++;
|
||||
len_block--;
|
||||
len--;
|
||||
if (len_block < 6) break;
|
||||
|
||||
sti.start_frame = framecnt + video_frames_avail + (dataptr[0] | ((int)dataptr[1] << 8));
|
||||
dataptr+=2;
|
||||
len-=2;
|
||||
len_block-=2;
|
||||
|
||||
sti.end_frame = sti.start_frame + (dataptr[0] | ((int)dataptr[1] << 8) | ((int)dataptr[2] << 16) | ((int)dataptr[3] << 24));
|
||||
dataptr+=4;
|
||||
len-=4;
|
||||
len_block-=4;
|
||||
|
||||
// set defaults for color/position
|
||||
sti.xPos=128;
|
||||
sti.yPos=255;
|
||||
sti.colorRed=255;
|
||||
sti.colorGreen=255;
|
||||
sti.colorBlue=255;
|
||||
sti.fontSize=0;
|
||||
|
||||
if (len_block >= 2)
|
||||
{
|
||||
sti.xPos = *dataptr++;
|
||||
sti.yPos = *dataptr++;
|
||||
len-=2;
|
||||
len_block-=2;
|
||||
if (len_block >= 3)
|
||||
{
|
||||
sti.colorRed=*dataptr++;
|
||||
sti.colorGreen=*dataptr++;
|
||||
sti.colorBlue=*dataptr++;
|
||||
len-=3;
|
||||
len_block-=3;
|
||||
if (len_block > 0)
|
||||
{
|
||||
sti.fontSize=(signed char) *dataptr++;
|
||||
len--;
|
||||
len_block--;
|
||||
}
|
||||
|
||||
if (len_block > 0)
|
||||
{
|
||||
sti.extraData=dataptr;
|
||||
sti.extraDataSize=len_block;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Subtitles *sub=findSubtitles(sti.language);
|
||||
if(!sub) sub=insertSubtitlesItem(sti.language,NULL);
|
||||
sub->addSubtitlePacket(&sti);
|
||||
|
||||
if (len_block > 0)
|
||||
{
|
||||
len-=len_block;
|
||||
dataptr+=len_block;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int NSVDecoder::run(int * volatile quit) // returns -1 on error, 0 if no frames processed, 1 if frames processed, 2 if underrun
|
||||
{
|
||||
int retval=0;
|
||||
|
||||
|
||||
if (!file_reader) return -1;
|
||||
|
||||
if (!aud_decoder_isnotnull && !vid_decoder_isnotnull && vid_decoder && aud_decoder)
|
||||
{
|
||||
m_err="Codec(s) not found";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aud_output && vidout_ready)
|
||||
{
|
||||
ULONGLONG curpos=aud_output->getpos();
|
||||
if (!m_paused)
|
||||
{
|
||||
if (!audio_frames_avail && curpos == hack_l_curpos && unpacket.getEof())
|
||||
{
|
||||
hack_l_curpos=curpos;
|
||||
curpos += GetTickCount64() - hack_l_curpos_ot;
|
||||
}
|
||||
else
|
||||
{
|
||||
hack_l_curpos_ot=GetTickCount64();
|
||||
hack_l_curpos=curpos;
|
||||
}
|
||||
}
|
||||
|
||||
if (curpos >= vidout_time && !m_prebuffer)
|
||||
{
|
||||
if (vidout)
|
||||
{
|
||||
// send this to get the flip state updated so when toggled on-the-fly it will work with nsv
|
||||
m_out->extended(0x1002/*VIDUSER_SET_VFLIP*/,vid_flip,0);
|
||||
m_out->draw(vidout);
|
||||
}
|
||||
|
||||
if (m_enable_subtitles)
|
||||
{
|
||||
SubtitlesItem *it=m_subtitles.get(m_cur_subtitle);
|
||||
if(it && config_subtitles) {
|
||||
it->m_subs->setFontSizeModifier(m_subs_fontsize);
|
||||
m_out->drawSubtitle(it->m_subs->getSubtitle((unsigned int)aud_output->getpos(),framecnt));
|
||||
}
|
||||
if ( it && !config_subtitles )
|
||||
{
|
||||
m_out->drawSubtitle(NULL);
|
||||
}
|
||||
}
|
||||
vidout=0;
|
||||
vidout_ready=0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hdrsearched && m_need_seek!=~0 && aud_output)
|
||||
{
|
||||
unsigned int newpos=m_need_seek;
|
||||
m_need_seek=~0;
|
||||
seek_dumpaudiosamples=0;
|
||||
seek_dumpframes=0;
|
||||
if (file_reader->canseek() && file_reader->getsize() != 0xFFFFFFFF)
|
||||
{
|
||||
int nbpos;
|
||||
|
||||
if (!fileheader.toc_size || !fileheader.toc || !fileheader.file_lenms ||
|
||||
!fileheader.file_lenbytes ||
|
||||
fileheader.file_lenms == 0xFFFFFFFF || fileheader.file_lenbytes == 0xFFFFFFFF)
|
||||
{
|
||||
int avg_framesize=avg_framesize_tot/avg_framesize_cnt;
|
||||
int pos_frames=(int)(newpos*getFrameRate());
|
||||
nbpos=fileheader.header_size+MulDiv(pos_frames,avg_framesize,1000);
|
||||
}
|
||||
else // calculate offset using TOC
|
||||
{
|
||||
if (fileheader.toc_ex) // use extended toc, find next earliest time closest
|
||||
{
|
||||
int x;
|
||||
double scale;
|
||||
if (unpacket.isValid() && getFrameRate() > 0.0001)
|
||||
scale=1000.0 / getFrameRate();
|
||||
else scale = 1000.0 / 30.0;
|
||||
for (x = 0; x < (int)fileheader.toc_size; x ++)
|
||||
{
|
||||
if (newpos < (unsigned int) (fileheader.toc_ex[x]*scale)) break;
|
||||
}
|
||||
unsigned int hdr[2]={0,0};
|
||||
if (--x >= 0)
|
||||
{
|
||||
hdr[0]=fileheader.toc[x];
|
||||
hdr[1]=(unsigned int) (fileheader.toc_ex[x] * scale);
|
||||
}
|
||||
//hdr[1] is the time of that keyframe
|
||||
|
||||
if (m_precise_seeking) // precise seek
|
||||
{
|
||||
int timediff = newpos - hdr[1];
|
||||
double fr;
|
||||
if (unpacket.isValid() && getFrameRate() >= 0.0001) fr = getFrameRate() / 1000.0;
|
||||
else fr = 30.0 / 1000.0;
|
||||
|
||||
seek_dumpframes=(int) (timediff * fr);
|
||||
seek_dumpaudiosamples=MulDiv(timediff,pcm_samplerate,1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
newpos=hdr[1];
|
||||
}
|
||||
|
||||
nbpos = fileheader.header_size + hdr[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
double tocpos=(newpos*(double)fileheader.toc_size)/(double)fileheader.file_lenms;
|
||||
unsigned int tocidx=(unsigned int)tocpos;
|
||||
if (tocidx > fileheader.toc_size)
|
||||
{
|
||||
nbpos=fileheader.header_size + fileheader.file_lenbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int a,b;
|
||||
if (tocidx<0) tocidx=0;
|
||||
a = fileheader.toc[tocidx];
|
||||
if (tocidx < fileheader.toc_size-1)
|
||||
b = fileheader.toc[tocidx+1];
|
||||
else b=fileheader.file_lenbytes;
|
||||
double frac=tocpos-tocidx;
|
||||
|
||||
nbpos = fileheader.header_size + (int) (a * (1.0 - frac) + b * frac);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!file_reader->seek(nbpos))
|
||||
{
|
||||
framecnt=(int)(newpos*getFrameRate()/1000.0);
|
||||
unpacket.reset(0);
|
||||
unpacket.setEof(0);
|
||||
hdrsearched=1;
|
||||
needkf=1;
|
||||
m_avresync_time=0;
|
||||
vidout=0;
|
||||
vidout_ready=0;
|
||||
video_frames_avail=0;
|
||||
audio_frames_avail=0;
|
||||
m_prebuffer=m_pb_init;
|
||||
inbs.clear();
|
||||
audiobs.clear();
|
||||
videobs.clear();
|
||||
auxbs.clear();
|
||||
if (aud_output) aud_output->flush(newpos);
|
||||
if (aud_decoder) aud_decoder->flush();
|
||||
if (vid_decoder) vid_decoder->flush();
|
||||
}
|
||||
}
|
||||
} // end of seeking
|
||||
|
||||
if (!hdrsearched) // search for header
|
||||
{
|
||||
readagain_header:
|
||||
if (quit && *quit) return 0;
|
||||
int ret=nsv_readheader(inbs,&fileheader);
|
||||
if (ret <= 0)
|
||||
{
|
||||
hdrsearched++;
|
||||
if (!ret)
|
||||
{
|
||||
_locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
|
||||
char *v=getFromMeta("ASPECT");
|
||||
if (v)
|
||||
{
|
||||
aspect=_atof_l(v,C_locale);
|
||||
}
|
||||
free(v);
|
||||
v=getFromMeta("FRAMERATE");
|
||||
if (v)
|
||||
{
|
||||
framerate_override=_atof_l(v,C_locale);
|
||||
if (framerate_override >= 0.01) use_framerate_override=1;
|
||||
free(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[8192] = {0};
|
||||
size_t ret2=file_reader->read(buf,sizeof(buf));
|
||||
|
||||
if (file_reader->iseof()) unpacket.setEof(1);
|
||||
|
||||
if (file_reader->geterror())
|
||||
{
|
||||
m_err=file_reader->geterror();
|
||||
return -1;
|
||||
}
|
||||
if (ret2>0)
|
||||
{
|
||||
inbs.add(buf, (int)ret2);
|
||||
goto readagain_header;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hdrsearched) return 0;
|
||||
// end of header search
|
||||
|
||||
// read from source
|
||||
if (m_prebuffer ||
|
||||
(((!unpacket.isValid() || audio_frames_avail < (int)((getFrameRate() * m_buffer_total)/1000.0)) || !videobs.avail()) &&
|
||||
(!m_buf_memlimit || ((int)(audiobs.avail()+videobs.avail()) < m_buf_memlimit*8))))
|
||||
{
|
||||
readagain_stream:
|
||||
if (quit && *quit) return 0;
|
||||
int lavail= (int)inbs.avail();
|
||||
|
||||
int ret=unpacket.unpacket(inbs);
|
||||
|
||||
inbs.compact();
|
||||
|
||||
if (ret)
|
||||
{
|
||||
if (!unpacket.isValid() && nsvbitstream_search > 8*1024*1024) // only scan for 8mb max
|
||||
{
|
||||
m_err="Error synching to NSV stream";
|
||||
return -1;
|
||||
}
|
||||
if (unpacket.getEof())
|
||||
{
|
||||
if (!videobs.avail() && !video_frames_avail && (!aud_output || aud_output->isplaying() <= 0)) retval=-1;
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[8192] = {0};
|
||||
|
||||
size_t ret2=file_reader->read(buf,sizeof(buf));
|
||||
|
||||
if (ret2 == 0 && file_reader->iseof())
|
||||
{
|
||||
m_prebuffer=0;
|
||||
unpacket.setEof(1);
|
||||
}
|
||||
|
||||
if (file_reader->geterror())
|
||||
{
|
||||
m_err=file_reader->geterror();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret2 > 0)
|
||||
{
|
||||
nsvbitstream_search+= (int)ret2;
|
||||
inbs.add(buf, (int)ret2);
|
||||
goto readagain_stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nsvbitstream_search=0;
|
||||
video_frames_avail++;
|
||||
audio_frames_avail++;
|
||||
nsv_type_to_string(unpacket.getAudFmt(),m_audio_type);
|
||||
nsv_type_to_string(unpacket.getVidFmt(),m_video_type);
|
||||
|
||||
avg_framesize_cnt++;
|
||||
avg_framesize_tot+=lavail- (int)((inbs.avail())/8);
|
||||
if (avg_framesize_tot > 0x80000000)
|
||||
{
|
||||
avg_framesize_tot/=2;
|
||||
avg_framesize_cnt/=2;
|
||||
}
|
||||
|
||||
if (1)
|
||||
{
|
||||
//parse aux packets
|
||||
while (auxbs.avail() >= 8*8)
|
||||
{
|
||||
size_t thislen = auxbs.getbits(32);
|
||||
unsigned int thistype = auxbs.getbits(32);
|
||||
if (thislen > auxbs.avail()/8) break;
|
||||
|
||||
if (thistype == NSV_MAKETYPE('S','U','B','T') ) ProcessSubtitleBlock(auxbs.getcurbyteptr(), (int)thislen);
|
||||
else if (thistype == NSV_MAKETYPE('A','S','Y','N'))
|
||||
{
|
||||
//if (thislen == 0) // resyncpoint
|
||||
{
|
||||
audiobs.addint(-1);
|
||||
audiobs.addint(framecnt+video_frames_avail);
|
||||
}
|
||||
//else // handle other form [todo]
|
||||
//{
|
||||
//}
|
||||
}
|
||||
|
||||
auxbs.seek(thislen*8);
|
||||
}
|
||||
}
|
||||
auxbs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (unpacket.isValid() && !m_prebuffer && !audiobs.avail() && aud_output)
|
||||
{
|
||||
if (aud_output->isplaying()) aud_output->write(0,0);
|
||||
else if (!unpacket.getEof())
|
||||
{
|
||||
m_prebuffer=m_pb_init_ur+(int)((video_frames_avail/getFrameRate())*1000.0);
|
||||
if (m_prebuffer < m_pb_init_ur) m_prebuffer=m_pb_init_ur;
|
||||
if (m_prebuffer > m_pb_init_ur*3) m_prebuffer=m_pb_init_ur*3;
|
||||
retval=2;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_frames_avail > (int)((m_prebuffer*getFrameRate())/1000.0))
|
||||
{
|
||||
m_bufstate=256;
|
||||
m_prebuffer=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int a = (int) (video_frames_avail * 256.0 / ((m_prebuffer*getFrameRate())/1000.0));
|
||||
if (a > 255) a=255;
|
||||
if (a < 0) a=0;
|
||||
m_bufstate=a;
|
||||
if (m_out) m_out->notifyBufferState(a);
|
||||
}
|
||||
|
||||
if (unpacket.isValid() && !vidout_ready && videobs.avail() && !m_prebuffer) // decode frame
|
||||
{
|
||||
if (!vid_decoder)
|
||||
{
|
||||
vid_flip=0;
|
||||
vid_decoder = CreateVideoDecoder(unpacket.getWidth(),unpacket.getHeight(),
|
||||
getFrameRate(),unpacket.getVidFmt(),&vid_flip,&vid_decoder_isnotnull);
|
||||
}
|
||||
|
||||
int kf=0;
|
||||
int l=videobs.getbits(32);
|
||||
unsigned int local_vidout_type[3] = { 1, 0, 0 };
|
||||
int ret=vid_decoder->decode(needkf,videobs.getcurbyteptr(),l,&vidout,local_vidout_type,&kf);
|
||||
vidout_type = local_vidout_type[0];
|
||||
if (ret == 0)
|
||||
{
|
||||
|
||||
vidout_codec_width = local_vidout_type[1];
|
||||
vidout_codec_height = local_vidout_type[2];
|
||||
}
|
||||
|
||||
if (kf) needkf=0;
|
||||
video_frames_avail--;
|
||||
videobs.seek(l*8);
|
||||
videobs.compact();
|
||||
|
||||
avg_framesize_cnt_v++;
|
||||
avg_framesize_tot_v+=l;
|
||||
|
||||
if (needkf || seek_dumpframes > 0)
|
||||
{
|
||||
vidout=NULL;
|
||||
if (seek_dumpframes>0) seek_dumpframes--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_out_opened && vid_decoder_isnotnull)
|
||||
{
|
||||
m_out->extended(0x1008/*VIDUSER_SET_THREAD_SAFE*/, 1, 0);
|
||||
unsigned int vidwidth = vidout_codec_width, vidheight = vidout_codec_height;
|
||||
if (vidwidth && vidheight)
|
||||
{
|
||||
/* if the codec provided a width/height to use */
|
||||
double aspect_adjust = (double)vidwidth / (double)vidheight / ((double)unpacket.getWidth() / (double)unpacket.getHeight());
|
||||
if (m_out->open(vidwidth,vidheight,vid_flip,aspect * aspect_adjust,vidout_type))
|
||||
{
|
||||
m_err="Error opening video output";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_out->open(unpacket.getWidth(),unpacket.getHeight(),vid_flip,aspect,vidout_type))
|
||||
{
|
||||
m_err="Error opening video output";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
m_out_opened=1;
|
||||
}
|
||||
|
||||
vidout_ready=1;
|
||||
vidout_time = (unsigned int)(framecnt++ / getFrameRate() * 1000.0) + (unsigned int)m_avresync_time;
|
||||
int offs=unpacket.getSyncOffset() + m_out->get_latency();
|
||||
|
||||
if ((int)vidout_time <= offs) vidout_time=0;
|
||||
else vidout_time-=offs;
|
||||
|
||||
//drop the image if we're late
|
||||
if(aud_output && vidout_time<aud_output->getpos()) {
|
||||
vidout=0;
|
||||
vidout_ready=0;
|
||||
}
|
||||
}
|
||||
|
||||
retval=1;
|
||||
}
|
||||
|
||||
if ( ( audiobs.avail() && !m_prebuffer ) || m_again )
|
||||
{
|
||||
if (needkf)
|
||||
{
|
||||
int l=audiobs.getbits(32);
|
||||
if (l == -1) audiobs.seek(32); // skip over 32 bits of our audiobs info
|
||||
else
|
||||
{
|
||||
audiobs.seek(l*8);
|
||||
audio_frames_avail--;
|
||||
}
|
||||
|
||||
audiobs.compact();
|
||||
}
|
||||
else // decode some audio
|
||||
{
|
||||
char pcmbuf[16384] = {0};
|
||||
int outbufl=512;
|
||||
if (!aud_decoder)
|
||||
{
|
||||
aud_decoder=CreateAudioDecoder(unpacket.getAudFmt(),&aud_decoder_isnotnull,&aud_output);
|
||||
if (aud_output && m_paused) aud_output->pause(1);
|
||||
}
|
||||
|
||||
if (aud_output) outbufl=aud_output->canwrite();
|
||||
|
||||
if (outbufl)
|
||||
{
|
||||
unsigned int outfmt[8] = {0};
|
||||
|
||||
retval=1;
|
||||
if (outbufl > sizeof(pcmbuf)) outbufl=sizeof(pcmbuf);
|
||||
|
||||
int inl=audiobs.getbits(32);
|
||||
|
||||
if (inl == -1)
|
||||
{
|
||||
int vidframe=audiobs.getbits(32);
|
||||
if (aud_output)
|
||||
{
|
||||
ULONGLONG audpos = aud_output->getwritepos();
|
||||
int vidpos = (int)(vidframe / getFrameRate() * 1000.0);
|
||||
|
||||
m_avresync_time = audpos-vidpos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret=aud_decoder->decode(audiobs.getcurbyteptr(), inl, pcmbuf, &outbufl, outfmt);
|
||||
|
||||
if ( !outbufl ) m_again = 0;
|
||||
else m_again =1;
|
||||
|
||||
if (ret < 1)
|
||||
{
|
||||
avg_framesize_cnt_a++;
|
||||
avg_framesize_tot_a+=inl;
|
||||
audiobs.seek(inl*8);
|
||||
audiobs.compact();
|
||||
audio_frames_avail--;
|
||||
}
|
||||
else audiobs.seek(-32);
|
||||
|
||||
if (outbufl || outfmt[0])
|
||||
{
|
||||
if (!aud_output)
|
||||
{
|
||||
aud_output=PCMOUT_CREATE(outfmt);
|
||||
pcm_samplerate=outfmt[1];
|
||||
if (!aud_output) aud_output = new NullAudioOutput;
|
||||
aud_output->setvolume(m_volume);
|
||||
aud_output->setpan(m_pan);
|
||||
if (aud_output && m_paused) aud_output->pause(1);
|
||||
}
|
||||
if (outbufl)
|
||||
{
|
||||
if (seek_dumpaudiosamples)
|
||||
{
|
||||
int nch=outfmt[2];
|
||||
int bps=outfmt[3];
|
||||
int dump=seek_dumpaudiosamples*nch*(bps/8);
|
||||
if (dump >= outbufl)
|
||||
{
|
||||
seek_dumpaudiosamples -= outbufl/nch/(bps/8);
|
||||
}
|
||||
else // partial write
|
||||
{
|
||||
aud_output->write(pcmbuf+dump,outbufl-dump);
|
||||
seek_dumpaudiosamples=0;
|
||||
}
|
||||
}
|
||||
else aud_output->write(pcmbuf,outbufl);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // if can write
|
||||
} //end of decode
|
||||
} // audiobs avail
|
||||
|
||||
if (m_prebuffer)
|
||||
#ifdef _WIN32
|
||||
Sleep(10);
|
||||
#else
|
||||
usleep(10000);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
Subtitles *NSVDecoder::insertSubtitlesItem(const char *language, const char *subfile) {
|
||||
Subtitles *sub=new Subtitles(subfile);
|
||||
m_subtitles.put(new SubtitlesItem(language, sub));
|
||||
return sub;
|
||||
}
|
||||
|
||||
Subtitles *NSVDecoder::findSubtitles(const char *language) {
|
||||
for(int i=0;i<m_subtitles.getlen();i++) {
|
||||
SubtitlesItem *s=m_subtitles.get(i);
|
||||
if(!_stricmp(language,s->m_language) ) return s->m_subs;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *NSVDecoder::getSubLanguage(int index) {
|
||||
if(index>=m_subtitles.getlen()) return NULL;
|
||||
return m_subtitles.get(index)->m_language;
|
||||
}
|
464
Src/nsv/nsvplay/nsvplay.dsp
Normal file
464
Src/nsv/nsvplay/nsvplay.dsp
Normal file
@ -0,0 +1,464 @@
|
||||
# Microsoft Developer Studio Project File - Name="nsvplay" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Application" 0x0101
|
||||
|
||||
CFG=nsvplay - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "nsvplay.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "nsvplay.mak" CFG="nsvplay - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "nsvplay - Win32 Release" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "nsvplay - Win32 Debug" (based on "Win32 (x86) Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "nsvplay - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "USE_ASM" /D "NO_LAYER12" /D "DLL_DECODER_SUPPORT" /D "BUILTIN_MP3_SUPPORT" /D "BUILTIN_VP3_SUPPORT" /D "SUBTITLES_READER" /FD /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib ddraw.lib wsock32.lib vfw32.lib /nologo /subsystem:windows /machine:I386 /out:"c:\nsv\nsvplay.exe"
|
||||
|
||||
!ELSEIF "$(CFG)" == "nsvplay - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "BUILTIN_VFW_SUPPORT" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "USE_ASM" /D "NO_LAYER12" /D "DLL_DECODER_SUPPORT" /D "BUILTIN_MP3_SUPPORT" /D "BUILTIN_VP3_SUPPORT" /D "SUBTITLES_READER" /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ddraw.lib winmm.lib wsock32.lib vfw32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"c:\nsv\nsvplay.exe" /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "nsvplay - Win32 Release"
|
||||
# Name "nsvplay - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Group "audio"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\audiostub.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\audiostub.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "vp3"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\vp32\include\duck_dxl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vp3stub.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vp3stub.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\vp32\lib\win32\Release\s_cpuid.lib
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\vp32\lib\win32\Release\s_dxv.lib
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\vp32\lib\win32\Release\s_sal.lib
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\vp32\lib\win32\Release\s_vp31d.lib
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "mp3dec"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "fhg"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\bitsequence.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\bitstream.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\bitstream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\conceal.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\conceal.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\crc16.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\crc16.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\giobase.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\huffdec.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\huffdec.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\huffmanbitobj.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\huffmandecoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\huffmandecoder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\huffmantable.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\huffmantable.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\l3table.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\l3table.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mdct.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mdct.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp2decode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp2decode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3decode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3decode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3quant.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3quant.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3read.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3read.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3ssc.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3ssc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3sscdef.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3streaminfo.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3tools.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mp3tools.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mpeg.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mpegbitstream.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mpegbitstream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mpegheader.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mpegheader.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mpgadecoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\mpgadecoder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\polyphase.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\mp3dec\polyphase.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mp3stub.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mp3stub.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "nsv"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\nsvbs.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\nsvlib.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\nsvlib.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "jnetlib"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\asyncdns.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\asyncdns.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\connection.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\connection.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\httpget.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\httpget.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\jnetlib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\netinc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\util.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\jnetlib\util.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "video"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vid_ddraw.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vid_ddraw.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vid_overlay.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vid_overlay.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\video.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\video.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\about.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\decoders.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\main.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nsvdecode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nsvplay.rc
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\readers.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\subtitles.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wndmenu.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\main.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\subtitles.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nsv_logo.bmp
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
29
Src/nsv/nsvplay/nsvplay.dsw
Normal file
29
Src/nsv/nsvplay/nsvplay.dsw
Normal file
@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "nsvplay"=.\nsvplay.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
106
Src/nsv/nsvplay/nsvplay.rc
Normal file
106
Src/nsv/nsvplay/nsvplay.rc
Normal file
@ -0,0 +1,106 @@
|
||||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_ABOUT DIALOG DISCARDABLE 0, 0, 184, 54
|
||||
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "About..."
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "OK",IDOK,105,33,50,14
|
||||
CTEXT "Static",IDC_VERSION,74,7,103,8
|
||||
CTEXT "Copyright (C) 2003 Nullsoft",IDC_STATIC,74,16,103,8
|
||||
CONTROL 102,IDC_STATIC,"Static",SS_BITMAP,7,7,67,39
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO DISCARDABLE
|
||||
BEGIN
|
||||
IDD_ABOUT, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 177
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 47
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bitmap
|
||||
//
|
||||
|
||||
IDB_BITMAP1 BITMAP DISCARDABLE "nsv_logo.bmp"
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
949
Src/nsv/nsvplay/readers.cpp
Normal file
949
Src/nsv/nsvplay/readers.cpp
Normal file
@ -0,0 +1,949 @@
|
||||
#include <windows.h>
|
||||
#include "main.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef NO_WASABI
|
||||
#include "../../jnetlib/httpget.h"
|
||||
api_httpreceiver *CreateGet()
|
||||
{
|
||||
return new JNL_HTTPGet;
|
||||
}
|
||||
|
||||
void ReleaseGet(api_httpreceiver *&get)
|
||||
{
|
||||
delete (JNL_HTTPGet *)get;
|
||||
get=0;
|
||||
}
|
||||
#else
|
||||
#include "../..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
#include <api.h>
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include "../../Winamp/in2.h"
|
||||
extern In_Module mod;
|
||||
|
||||
waServiceFactory *httpFactory = 0;
|
||||
api_httpreceiver *CreateGet()
|
||||
{
|
||||
api_httpreceiver *get = 0;
|
||||
if (!httpFactory && mod.service)
|
||||
httpFactory = mod.service->service_getServiceByGuid(httpreceiverGUID);
|
||||
|
||||
if (httpFactory)
|
||||
get = (api_httpreceiver *)httpFactory->getInterface();
|
||||
|
||||
return get;
|
||||
}
|
||||
|
||||
void ReleaseGet(api_httpreceiver *&get)
|
||||
{
|
||||
if (!get)
|
||||
return ;
|
||||
|
||||
if (!httpFactory && mod.service)
|
||||
waServiceFactory *sf = mod.service->service_getServiceByGuid(httpreceiverGUID);
|
||||
|
||||
if (httpFactory)
|
||||
httpFactory->releaseInterface(get);
|
||||
|
||||
get = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#define MAX_MULTICONNECTS 8
|
||||
|
||||
class HTTPReader : public IDataReader
|
||||
{
|
||||
public:
|
||||
HTTPReader(const char *url);
|
||||
~HTTPReader();
|
||||
size_t read(char *buf, size_t len);
|
||||
bool iseof() { return !!m_eof; }
|
||||
char *gettitle() { return m_title; }
|
||||
char *geterror() { return m_err; }
|
||||
bool canseek() { return m_content_length != 0xFFFFFFFF && m_accept_ranges && !m_meta_interval; }
|
||||
int seek(unsigned __int64 newpos)
|
||||
{
|
||||
if (!canseek()) return 1;
|
||||
doConnect((int)newpos);
|
||||
return 0;
|
||||
}
|
||||
unsigned __int64 getsize() { return m_content_length; }
|
||||
char *getheader(char *header_name)
|
||||
{
|
||||
return m_get ? (char *)m_get->getheader(header_name) : NULL;
|
||||
}
|
||||
private:
|
||||
|
||||
int serialconnect( int seekto , int timeout);
|
||||
void doConnect(int seekto);
|
||||
int getProxyInfo(const char *url, char *out);
|
||||
char *m_url;
|
||||
char *m_err;
|
||||
char *m_title;
|
||||
int m_eof;
|
||||
int m_meta_init, m_meta_interval, m_meta_pos, m_meta_size, m_meta_buf_pos;
|
||||
char m_meta_buf[4096];
|
||||
int m_read_headers;
|
||||
unsigned int m_content_length;
|
||||
int m_accept_ranges;
|
||||
int m_is_uvox;
|
||||
int m_uvox_readpos;
|
||||
int m_uvox_enough_bytes;
|
||||
char proxybuf[8400], *proxy;
|
||||
|
||||
api_httpreceiver *m_get;
|
||||
|
||||
// this structure is allocated once, and freed once
|
||||
struct
|
||||
{
|
||||
char *url; //pointers into m_url
|
||||
// these two are only active temporarily.
|
||||
api_httpreceiver *get;
|
||||
char *error;
|
||||
}
|
||||
m_cons[MAX_MULTICONNECTS];
|
||||
int m_numcons;
|
||||
int m_newcons;
|
||||
int m_serialized;
|
||||
int m_mstimeout;
|
||||
int m_contryptr;
|
||||
int m_serialfailed;
|
||||
int m_useaproxy;
|
||||
};
|
||||
|
||||
HTTPReader::HTTPReader(const char *url)
|
||||
{
|
||||
m_title = 0;
|
||||
m_is_uvox = m_uvox_readpos = 0;
|
||||
m_meta_init = m_meta_interval = m_meta_pos = m_meta_size = m_meta_buf_pos = 0;
|
||||
m_meta_buf[0] = 0;
|
||||
m_err = NULL;
|
||||
m_eof = 0;
|
||||
m_read_headers = 0;
|
||||
m_content_length = 0xFFFFFFFF;
|
||||
m_accept_ranges = 0;
|
||||
m_get = NULL;
|
||||
m_serialized = 0;
|
||||
m_mstimeout = 0;
|
||||
m_contryptr = 0;
|
||||
m_newcons = 0;
|
||||
m_serialfailed = 0;
|
||||
m_useaproxy = 0;
|
||||
|
||||
// TCP multiconnect
|
||||
// JF> using ; as a delimiter is vomit inducing and breaks a lot of other
|
||||
// code. I petition we use <> to delimit, and I'm making it do that.
|
||||
|
||||
m_numcons = 0;
|
||||
m_url = _strdup(url);
|
||||
|
||||
int allowproxy = 1;
|
||||
char *tmpurl = m_url;
|
||||
while (m_numcons < MAX_MULTICONNECTS)
|
||||
{
|
||||
char *next = strstr( tmpurl, "<>" );
|
||||
if ( next ) *next = '\0';
|
||||
|
||||
if (tmpurl[0])
|
||||
{
|
||||
m_cons[m_numcons].error = NULL;
|
||||
m_cons[m_numcons].get = NULL;
|
||||
m_cons[m_numcons++].url = tmpurl;
|
||||
if (!_strnicmp(tmpurl, "uvox:", 5)) allowproxy = 0;
|
||||
if (!_strnicmp(tmpurl, "order://", 8))
|
||||
{
|
||||
char *p = tmpurl + 8;
|
||||
// serialized mctp
|
||||
m_serialized = 1;
|
||||
m_numcons--;
|
||||
m_mstimeout = atoi(p);
|
||||
if ( m_mstimeout < 1 )
|
||||
{
|
||||
m_serialized = 0;
|
||||
m_mstimeout = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!next) break;
|
||||
|
||||
tmpurl = next + 2;
|
||||
}
|
||||
|
||||
memset(proxybuf, 0, sizeof(proxybuf));
|
||||
proxy = NULL;
|
||||
if (allowproxy && getProxyInfo(url, proxybuf))
|
||||
{
|
||||
proxy = strstr(proxybuf, "http=");
|
||||
if (!proxy) proxy = proxybuf;
|
||||
else
|
||||
{
|
||||
proxy += 5;
|
||||
char *tp = strstr(proxy, ";");
|
||||
if (tp) *tp = 0;
|
||||
}
|
||||
}
|
||||
m_is_uvox = 0;
|
||||
|
||||
if ( m_serialized && m_numcons > 1 ) // sanity check
|
||||
{
|
||||
int rval = 0, i;
|
||||
m_newcons = 1;
|
||||
// walk the list, set the url such that m_cons[0].url points to each item. try to connect
|
||||
// serialconnect returns error codes -1 on error, 0 on timeout, 1 on successfull connect
|
||||
for ( i = 0; i < m_numcons; i++ )
|
||||
{
|
||||
if ( i )
|
||||
{
|
||||
m_cons[0].url = m_cons[i].url;
|
||||
}
|
||||
rval = serialconnect(0, m_mstimeout);
|
||||
if ( rval == 1 ) break;
|
||||
}
|
||||
if ( rval < 1 )
|
||||
{
|
||||
// we didnt get a connection so...
|
||||
m_serialfailed = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
doConnect(0);
|
||||
}
|
||||
|
||||
|
||||
void HTTPReader::doConnect(int seekto)
|
||||
{
|
||||
ReleaseGet(m_get);
|
||||
m_uvox_readpos = 0;
|
||||
|
||||
m_eof = 0;
|
||||
|
||||
|
||||
int i;
|
||||
for (i = 0; i < m_numcons; i++ )
|
||||
{
|
||||
free(m_cons[i].error);
|
||||
m_cons[i].error = NULL;
|
||||
ReleaseGet(m_cons[i].get);
|
||||
m_cons[i].get = CreateGet();
|
||||
if (!m_cons[i].get)
|
||||
break;
|
||||
m_cons[i].get->open(API_DNS_AUTODNS, 65536, (proxy && proxy[0]) ? proxy : NULL);
|
||||
#ifdef WINAMP_PLUGIN
|
||||
m_cons[i].get->addheader("User-Agent:Winamp NSV Player/5.12 (ultravox/2.0)");
|
||||
#else
|
||||
# ifdef WINAMPX
|
||||
m_cons[i].get->addheader("User-Agent:" UNAGI_USER_AGENT " (ultravox/2.0)");
|
||||
# else
|
||||
m_cons[i].get->addheader("User-Agent:NSV Player/0.0 (ultravox/2.0)");
|
||||
# endif
|
||||
#endif
|
||||
m_cons[i].get->addheader("Accept:*/*");
|
||||
m_cons[i].get->addheader("Connection:close");
|
||||
m_cons[i].get->addheader("Ultravox-transport-type: TCP");
|
||||
|
||||
if (seekto)
|
||||
{
|
||||
char buf[64] = {0};
|
||||
wsprintfA(buf, "Range:bytes=%d-", seekto);
|
||||
m_cons[i].get->addheader(buf);
|
||||
}
|
||||
else
|
||||
m_cons[i].get->addheader("icy-metadata:1");
|
||||
|
||||
m_cons[i].get->connect(m_cons[i].url, !!seekto);
|
||||
}
|
||||
m_uvox_enough_bytes = 1;
|
||||
}
|
||||
|
||||
HTTPReader::~HTTPReader()
|
||||
{
|
||||
ReleaseGet(m_get);
|
||||
free(m_title);
|
||||
free(m_err);
|
||||
free(m_url);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < m_numcons; i++)
|
||||
{
|
||||
ReleaseGet(m_cons[i].get);
|
||||
free(m_cons[i].error);
|
||||
}
|
||||
}
|
||||
|
||||
int HTTPReader::serialconnect(int seekto , int timeout)
|
||||
{
|
||||
|
||||
ReleaseGet(m_get);
|
||||
m_uvox_readpos = 0;
|
||||
|
||||
m_eof = 0;
|
||||
|
||||
int64_t mythen, mynow , myref;
|
||||
LARGE_INTEGER then, now, ref;
|
||||
|
||||
|
||||
QueryPerformanceFrequency( &ref);
|
||||
myref = ref.QuadPart;
|
||||
|
||||
|
||||
QueryPerformanceCounter( &then );
|
||||
mythen = then.QuadPart;
|
||||
|
||||
|
||||
int timer = 0;
|
||||
|
||||
int i = 0;
|
||||
|
||||
{
|
||||
ReleaseGet(m_cons[i].get);
|
||||
m_cons[i].get = CreateGet();
|
||||
if (m_cons[i].get == NULL)
|
||||
return 0;
|
||||
m_cons[i].get->open(API_DNS_AUTODNS, 65536, (proxy && proxy[0]) ? proxy : NULL);
|
||||
#ifdef WINAMP_PLUGIN
|
||||
m_cons[i].get->addheader("User-Agent:Winamp NSV Player/5.12 (ultravox/2.0)");
|
||||
#else
|
||||
# ifdef WINAMPX
|
||||
m_cons[i].get->addheader("User-Agent:" UNAGI_USER_AGENT " (ultravox/2.0)");
|
||||
# else
|
||||
m_cons[i].get->addheader("User-Agent:NSV Player/0.0 (ultravox/2.0)");
|
||||
# endif
|
||||
#endif
|
||||
m_cons[i].get->addheader("Accept:*/*");
|
||||
m_cons[i].get->addheader("Connection:close");
|
||||
m_cons[i].get->addheader("Ultravox-transport-type: TCP");
|
||||
|
||||
if (seekto)
|
||||
{
|
||||
char buf[64] = {0};
|
||||
wsprintfA(buf, "Range:bytes=%d-", seekto);
|
||||
m_cons[i].get->addheader(buf);
|
||||
}
|
||||
else m_cons[i].get->addheader("icy-metadata:1");
|
||||
|
||||
m_cons[i].get->connect(m_cons[i].url, !!seekto);
|
||||
}
|
||||
m_uvox_enough_bytes = 1;
|
||||
|
||||
int ret, status;
|
||||
|
||||
if (!m_get)
|
||||
{
|
||||
if (m_err) return 0;
|
||||
int i;
|
||||
int found = 0;
|
||||
i = 0;
|
||||
while ( timer < timeout )
|
||||
{
|
||||
if (!m_cons[i].get) return 0;
|
||||
found = 1;
|
||||
|
||||
QueryPerformanceCounter( &now );
|
||||
mynow = now.QuadPart;
|
||||
|
||||
float profiletime = (float)(mynow - mythen);
|
||||
profiletime /= myref;
|
||||
profiletime *= 1000.0;
|
||||
timer = (int) profiletime;
|
||||
|
||||
ret = m_cons[i].get->run();
|
||||
status = m_cons[i].get->get_status();
|
||||
|
||||
if (ret < 0 || status < 0)
|
||||
{
|
||||
const char *t = m_cons[i].get->geterrorstr();
|
||||
if (t)
|
||||
{}
|
||||
ReleaseGet(m_cons[i].get);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( status > 0 )
|
||||
{
|
||||
int code = m_cons[i].get->getreplycode();
|
||||
if ( code < 200 || code > 299 )
|
||||
{
|
||||
ReleaseGet(m_cons[i].get);
|
||||
//wsprintf( m_cons[i].error, "Error: Server returned %d", code );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're in good shape, make our getter current, and delete all the gay ones
|
||||
ReleaseGet(m_get); // just in case, probably zero anyway
|
||||
m_get = m_cons[i].get;
|
||||
m_cons[i].get = NULL;
|
||||
|
||||
// trash i here, but we are breaking anyway :)
|
||||
/* for (i = 0; i < m_numcons; i++)
|
||||
{
|
||||
delete m_cons[i].get;
|
||||
m_cons[i].get = NULL;
|
||||
free( m_cons[i].error );
|
||||
m_cons[i].error = NULL;
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
Sleep(1);
|
||||
#else
|
||||
usleep(1000);
|
||||
#endif
|
||||
} // while
|
||||
if ( timer > timeout )
|
||||
{
|
||||
ReleaseGet(m_cons[i].get);
|
||||
ReleaseGet(m_get);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (!m_get)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ( m_get ) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t HTTPReader::read(char *buffer, size_t len)
|
||||
{
|
||||
int ret, status;
|
||||
|
||||
if (!m_get)
|
||||
{
|
||||
if (m_err) return 0;
|
||||
int i;
|
||||
int found = 0;
|
||||
for (i = 0; !m_get && i < m_numcons; i++)
|
||||
{
|
||||
if (!m_cons[i].get) continue;
|
||||
found = 1;
|
||||
|
||||
ret = m_cons[i].get->run();
|
||||
status = m_cons[i].get->get_status();
|
||||
|
||||
if (ret < 0 || status < 0)
|
||||
{
|
||||
const char *t = m_cons[i].get->geterrorstr();
|
||||
if (t)
|
||||
{
|
||||
free(m_cons[i].error);
|
||||
m_cons[i].error = _strdup( t );
|
||||
}
|
||||
ReleaseGet(m_cons[i].get);
|
||||
|
||||
}
|
||||
|
||||
if ( status > 0 )
|
||||
{
|
||||
int code = m_cons[i].get->getreplycode();
|
||||
if ( code < 200 || code > 299 )
|
||||
{
|
||||
ReleaseGet(m_cons[i].get);
|
||||
m_cons[i].get = NULL;
|
||||
|
||||
free(m_cons[i].error);
|
||||
m_cons[i].error = (char *)malloc( 100 );
|
||||
wsprintfA( m_cons[i].error, "Error: Server returned %d", code );
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're in good shape, make our getter current, and delete all the gay ones
|
||||
ReleaseGet(m_get); // just in case, probably zero anyway
|
||||
m_get = m_cons[i].get;
|
||||
m_cons[i].get = NULL;
|
||||
|
||||
// trash i here, but we are breaking anyway :)
|
||||
for (i = 0; i < m_numcons; i++)
|
||||
{
|
||||
ReleaseGet(m_cons[i].get);
|
||||
free( m_cons[i].error );
|
||||
m_cons[i].error = NULL;
|
||||
}
|
||||
break; // exit loop of connections
|
||||
}
|
||||
}
|
||||
} // loop of connections
|
||||
|
||||
if (!found) // out of attempted connections heh
|
||||
{
|
||||
free( m_err );
|
||||
if (m_numcons > 1)
|
||||
{
|
||||
size_t size = 0;
|
||||
for (i = 0; i < m_numcons; i++)
|
||||
if ( m_cons[i].error ) size += strlen( m_cons[i].error ) + 1;
|
||||
|
||||
m_err = (char *)malloc(size + 100);
|
||||
wsprintfA( m_err, "No Valid Multiconnect URLs (%d);", m_numcons );
|
||||
for (i = 0; i < m_numcons; i++)
|
||||
{
|
||||
strcat( m_err, m_cons[i].error );
|
||||
strcat( m_err, ";" );
|
||||
free(m_cons[i].error);
|
||||
m_cons[i].error = NULL;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_err = m_cons[0].error;
|
||||
m_cons[0].error = NULL;
|
||||
if (!m_err) m_err = _strdup("Connection error (Invalid URL?)");
|
||||
}
|
||||
}
|
||||
if (!m_get) return 0;
|
||||
}
|
||||
|
||||
ret = m_get->run();
|
||||
status = m_get->get_status();
|
||||
|
||||
if (ret > 0 && (!m_get->bytes_available() || !m_uvox_enough_bytes) && status > 1)
|
||||
{
|
||||
m_eof = 1;
|
||||
}
|
||||
|
||||
if (ret < 0 || status < 0)
|
||||
{
|
||||
const char *t = m_get->geterrorstr();
|
||||
if (t)
|
||||
{
|
||||
free( m_err );
|
||||
m_err = (char *)malloc( strlen( t) + 16 );
|
||||
wsprintfA( m_err, "Error: %s", t );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
if (!m_read_headers)
|
||||
{
|
||||
if (status > 1)
|
||||
{
|
||||
const char *v = m_get->getheader("Content-Length");
|
||||
if (v) m_content_length = atoi(v);
|
||||
v = m_get->getheader("Accept-Ranges");
|
||||
if (v) while (v && *v)
|
||||
{
|
||||
if (!_strnicmp(v, "bytes", 5))
|
||||
{
|
||||
m_accept_ranges = 1;
|
||||
break;
|
||||
}
|
||||
v++;
|
||||
}
|
||||
v = m_get->getheader("icy-metaint");
|
||||
if (v)
|
||||
{
|
||||
m_meta_interval = atoi(v);
|
||||
}
|
||||
if (!m_title)
|
||||
{
|
||||
v = m_get->getheader("icy-name");
|
||||
if (v)
|
||||
m_title = _strdup(v);
|
||||
}
|
||||
#ifdef WINAMP_PLUGIN
|
||||
extern void process_url(char *url);
|
||||
v = m_get->getheader("icy-url");
|
||||
if (v && !strstr(v, "shoutcast.com"))
|
||||
{
|
||||
char *p = (char *)v; while (p && *p && *p == ' ') p++;
|
||||
process_url(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
v = m_get->getheader("content-type");
|
||||
if (v && !_stricmp(v, "misc/ultravox"))
|
||||
{
|
||||
v = m_get->getheader("ultravox-max-msg");
|
||||
if (v) m_is_uvox = atoi(v);
|
||||
if (!m_is_uvox) m_is_uvox = 16000;
|
||||
}
|
||||
if (!m_title)
|
||||
{
|
||||
v = m_get->getheader("content-disposition");
|
||||
if (v) v = strstr(v, "filename=");
|
||||
if (v)
|
||||
{
|
||||
m_title = _strdup(v + 9);
|
||||
}
|
||||
}
|
||||
m_read_headers = 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t l = m_get->bytes_available();
|
||||
if (m_is_uvox)
|
||||
{
|
||||
again:
|
||||
if (l >= 6)
|
||||
{
|
||||
unsigned char buf[32768*2] = {0};
|
||||
m_get->peek_bytes((char *)buf, 6);
|
||||
if (buf[0] != 0x5A)
|
||||
{
|
||||
l--;
|
||||
m_get->get_bytes((char *)buf, 1);
|
||||
goto again;
|
||||
}
|
||||
int resqos = buf[1];
|
||||
int classtype = (buf[2] << 8) | buf[3];
|
||||
int msglen = (buf[4] << 8) | buf[5];
|
||||
if (msglen > m_is_uvox) // length is too long
|
||||
{
|
||||
m_get->get_bytes((char *)buf, 1);
|
||||
l--;
|
||||
goto again;
|
||||
}
|
||||
if (msglen + 7 <= (int)l)
|
||||
{
|
||||
m_uvox_enough_bytes = 1;
|
||||
|
||||
m_get->peek_bytes((char *)buf, msglen + 7);
|
||||
if (buf[msglen + 6])
|
||||
{
|
||||
m_get->get_bytes((char *)buf, 1);
|
||||
l--;
|
||||
goto again;
|
||||
}
|
||||
if (classtype == 0x7777) // take any data for now, ignore all other frames
|
||||
{
|
||||
l = msglen - m_uvox_readpos;
|
||||
if (l > len) l = len;
|
||||
memcpy(buffer, buf + 6 + m_uvox_readpos, l);
|
||||
m_uvox_readpos += (int)l;
|
||||
|
||||
if (m_uvox_readpos >= msglen)
|
||||
{
|
||||
m_uvox_readpos = 0;
|
||||
m_get->get_bytes((char *)buf, msglen + 7);
|
||||
|
||||
}
|
||||
return l;
|
||||
|
||||
#ifdef WINAMP_PLUGIN
|
||||
|
||||
}
|
||||
else if ( classtype == 0x3001 )
|
||||
{
|
||||
extern void process_metadata(char *buf, int size);
|
||||
m_get->get_bytes((char *)buf, msglen + 7);
|
||||
process_metadata((char*)buf + 6, msglen + 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_get->get_bytes((char *)buf, msglen + 7);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uvox_enough_bytes = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (l > len) l = len;
|
||||
m_get->get_bytes(buffer, (int)l);
|
||||
|
||||
if (m_meta_interval)
|
||||
{
|
||||
int x = (int)l;
|
||||
unsigned char *buf = (unsigned char *)buffer;
|
||||
if (m_meta_size) // already in meta block
|
||||
{
|
||||
int len = min(x, m_meta_size - m_meta_buf_pos);
|
||||
|
||||
memcpy(m_meta_buf + m_meta_buf_pos, buf, len);
|
||||
m_meta_buf_pos += len;
|
||||
|
||||
if (m_meta_buf_pos == m_meta_size)
|
||||
{
|
||||
// if(metacb) metacb->metaDataReader_onData(m_meta_buf,m_meta_size);
|
||||
m_meta_buf_pos = 0;
|
||||
m_meta_size = 0;
|
||||
m_meta_pos = 0;
|
||||
}
|
||||
|
||||
x -= len;
|
||||
if (x) memcpy(buf, buf + len, x);
|
||||
}
|
||||
else if (m_meta_pos + x > m_meta_interval) // block contains meta data somewhere in it, and we're not alreayd reading a block
|
||||
{
|
||||
int start_offs = m_meta_interval - m_meta_pos;
|
||||
int len;
|
||||
m_meta_size = ((unsigned char *)buf)[start_offs] * 16;
|
||||
|
||||
len = min(x - start_offs - 1, m_meta_size);
|
||||
|
||||
if (len) memcpy(m_meta_buf, buf + start_offs + 1, len);
|
||||
m_meta_buf_pos = len;
|
||||
|
||||
if (m_meta_buf_pos == m_meta_size) // full read of metadata successful
|
||||
{
|
||||
x -= m_meta_size + 1;
|
||||
if (x > start_offs) memcpy(buf + start_offs, buf + start_offs + 1 + m_meta_size, x - start_offs);
|
||||
#ifdef WINAMP_PLUGIN
|
||||
extern void process_metadata(char *buf, int size);
|
||||
process_metadata(m_meta_buf, m_meta_size);
|
||||
#endif
|
||||
//if(metacb) metacb->metaDataReader_onData(m_meta_buf,m_meta_size);
|
||||
m_meta_buf_pos = 0;
|
||||
m_meta_pos = -start_offs;
|
||||
m_meta_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = start_offs; // otherwise, there's only the first block of data
|
||||
}
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
m_meta_pos += x;
|
||||
}
|
||||
l = x;
|
||||
} // end of poopie metadata
|
||||
} // !uvox
|
||||
|
||||
#if 0
|
||||
{
|
||||
FILE *fh = fopen("c:\\dump.nsv", "ab");
|
||||
fwrite(buffer, 1, l, fh);
|
||||
fclose(fh);
|
||||
}
|
||||
#endif
|
||||
|
||||
return l;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parseURL(char *url, char *lp, char *host, int *port, char *req)
|
||||
{
|
||||
char *p, *np;
|
||||
/* if (_strnicmp(url,"http://",4) &&
|
||||
_strnicmp(url,"icy://",6) &&
|
||||
_strnicmp(url,"sc://",6) &&
|
||||
_strnicmp(url,"shoutcast://",12)) return;
|
||||
*/
|
||||
np = p = strstr(url, "://");
|
||||
if (!np) np = (char*)url;
|
||||
else np += 3;
|
||||
if (!p) p = (char*)url;
|
||||
else p += 3;
|
||||
|
||||
while (np && *np != '/' && *np) *np++;
|
||||
if (np && *np)
|
||||
{
|
||||
lstrcpynA(req, np, 2048);
|
||||
*np++ = 0;
|
||||
}
|
||||
else strcpy(req, "/");
|
||||
np = p;
|
||||
while (np && *np != '@' && *np) np++;
|
||||
if (np && *np)
|
||||
{
|
||||
*np++ = 0;
|
||||
lstrcpynA(lp, p, 256);
|
||||
p = np;
|
||||
}
|
||||
else lp[0] = 0;
|
||||
np = p;
|
||||
while (np && *np != ':' && *np) np++;
|
||||
if (*np)
|
||||
{
|
||||
*np++ = 0;
|
||||
*port = atoi(np);
|
||||
}
|
||||
else *port = 80;
|
||||
lstrcpynA(host, p, 256);
|
||||
}
|
||||
|
||||
int HTTPReader::getProxyInfo(const char *url, char *out)
|
||||
{
|
||||
#ifndef WINAMPX
|
||||
char INI_FILE[MAX_PATH] = {0};
|
||||
char *p;
|
||||
GetModuleFileNameA(NULL, INI_FILE, sizeof(INI_FILE));
|
||||
p = INI_FILE + strlen(INI_FILE);
|
||||
while (p >= INI_FILE && *p != '.') p--;
|
||||
strcpy(++p, "ini");
|
||||
GetPrivateProfileStringA("Winamp", "proxy", "", out, 8192, INI_FILE);
|
||||
return !!out[0];
|
||||
#else
|
||||
DWORD v = 0;
|
||||
HKEY hKey;
|
||||
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\AOL\\Unagi", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD l = 4;
|
||||
DWORD t;
|
||||
if (RegQueryValueEx(hKey, "ProxyEnable", NULL, &t, (unsigned char *)&v, &l) == ERROR_SUCCESS && t == REG_DWORD)
|
||||
{
|
||||
if ( v != 2 )
|
||||
{
|
||||
l = 8192;
|
||||
if (RegQueryValueEx(hKey, "ProxyServer", NULL, &t, (unsigned char *)out, &l ) != ERROR_SUCCESS || t != REG_SZ)
|
||||
{
|
||||
v = 0;
|
||||
*out = 0;
|
||||
}
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else v = 0;
|
||||
out[512 - 1] = 0;
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
if ( !v && m_useaproxy )
|
||||
{
|
||||
char blah[8192] = "";
|
||||
lstrcpyn(blah, url, 8192);
|
||||
char plp[512] = {0};
|
||||
char phost[512] = {0};
|
||||
int pport = 80;
|
||||
char pthereq[1024] = {0};
|
||||
parseURL(blah, plp, phost, &pport, pthereq);
|
||||
v = ResolvProxyFromURL(url, phost, out);
|
||||
if ( v < 0 ) v = 0; // error getting proxy
|
||||
}
|
||||
if ( v > 0)
|
||||
{
|
||||
char prox[1024] = {0};
|
||||
wsprintf(prox, "PROXY: %s", out);
|
||||
SendMetadata(prox, 1);
|
||||
}
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Win32FileReader : public IDataReader
|
||||
{
|
||||
public:
|
||||
Win32FileReader(HANDLE file) { m_hFile = file; m_eof = 0; m_err = NULL; }
|
||||
~Win32FileReader() { CloseHandle(m_hFile); }
|
||||
size_t read(char *buf, size_t len)
|
||||
{
|
||||
DWORD ob = 0;
|
||||
if (!len) return 0;
|
||||
if (!ReadFile(m_hFile, buf, (DWORD)len, &ob, NULL))
|
||||
{
|
||||
m_err = "Error calling ReadFile()!";
|
||||
return 0;
|
||||
}
|
||||
else if (!ob) m_eof = true;
|
||||
return ob;
|
||||
}
|
||||
bool iseof() { return m_eof; }
|
||||
bool canseek() { return 1; }
|
||||
int seek(uint64_t newpos)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = newpos;
|
||||
li.LowPart = SetFilePointer (m_hFile, li.LowPart, &li.HighPart, SEEK_SET);
|
||||
|
||||
if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
|
||||
{
|
||||
li.QuadPart = -1;
|
||||
}
|
||||
|
||||
return li.QuadPart== ~0;
|
||||
}
|
||||
|
||||
uint64_t getsize()
|
||||
{
|
||||
LARGE_INTEGER position;
|
||||
position.QuadPart=0;
|
||||
position.LowPart = GetFileSize(m_hFile, (LPDWORD)&position.HighPart);
|
||||
|
||||
if (position.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
|
||||
return INVALID_FILE_SIZE;
|
||||
else
|
||||
return position.QuadPart;
|
||||
}
|
||||
|
||||
char *geterror() { return m_err; }
|
||||
private:
|
||||
HANDLE m_hFile;
|
||||
bool m_eof;
|
||||
char *m_err;
|
||||
};
|
||||
|
||||
|
||||
#define VAR_TO_FPOS(fpos, var) (fpos) = (var)
|
||||
#define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)(fpos)
|
||||
class FileReader : public IDataReader
|
||||
{
|
||||
public:
|
||||
FileReader(FILE *file) { fp = file; m_err = NULL; }
|
||||
~FileReader() { fclose(fp); }
|
||||
size_t read(char *buf, size_t len)
|
||||
{
|
||||
size_t ob;
|
||||
if (!len) return 0;
|
||||
ob = fread(buf, 1, len, fp);
|
||||
if (!ob && ferror(fp))
|
||||
{
|
||||
m_err = "Error calling fread()!";
|
||||
return 0;
|
||||
}
|
||||
return ob;
|
||||
}
|
||||
bool iseof() { return !!feof(fp); }
|
||||
bool canseek() { return 1; }
|
||||
int seek(uint64_t newpos)
|
||||
{
|
||||
fpos_t pos= newpos;
|
||||
VAR_TO_FPOS(pos, newpos);
|
||||
return fsetpos(fp, &pos);
|
||||
}
|
||||
|
||||
unsigned __int64 getsize()
|
||||
{
|
||||
struct stat s;
|
||||
if (fstat(fileno(fp), &s) < 0)
|
||||
{
|
||||
m_err = "Error calling fread()!";
|
||||
return 0;
|
||||
}
|
||||
return s.st_size;
|
||||
}
|
||||
|
||||
char *geterror() { return m_err; }
|
||||
private:
|
||||
FILE *fp;
|
||||
char *m_err;
|
||||
};
|
||||
|
||||
|
||||
IDataReader *CreateReader(const char *url)
|
||||
{
|
||||
if (strstr(url, "://")) return new HTTPReader(url);
|
||||
#ifdef _WIN32
|
||||
HANDLE hFile = CreateFileA(url, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
return new Win32FileReader(hFile);
|
||||
#else
|
||||
FILE *fp = fopen(url, "r");
|
||||
if (fp)
|
||||
return new FileReader(fp);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
18
Src/nsv/nsvplay/resource.h
Normal file
18
Src/nsv/nsvplay/resource.h
Normal file
@ -0,0 +1,18 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by nsvplay.rc
|
||||
//
|
||||
#define IDD_ABOUT 101
|
||||
#define IDB_BITMAP1 102
|
||||
#define IDC_VERSION 1000
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
215
Src/nsv/nsvplay/subtitles.cpp
Normal file
215
Src/nsv/nsvplay/subtitles.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include "subtitles.h"
|
||||
|
||||
Subtitles::Subtitles(const char *filename)
|
||||
{
|
||||
m_frame_based=0;
|
||||
m_last_sub=-1;
|
||||
m_font_size_mod=0;
|
||||
|
||||
#ifdef SUBTITLES_READER
|
||||
if(!filename) return;
|
||||
|
||||
IDataReader *file_reader=CreateReader(filename);
|
||||
if(file_reader) {
|
||||
char *text=NULL;
|
||||
int textpos=0;
|
||||
int allocsize=0;
|
||||
char buf[1024] = {0};
|
||||
unsigned aborttime=GetTickCount()+20000;
|
||||
for (;;)
|
||||
{
|
||||
int l=file_reader->read(buf,1024);
|
||||
if (l <= 0)
|
||||
{
|
||||
if (file_reader->iseof()) break;
|
||||
if (file_reader->geterror() || GetTickCount() > aborttime)
|
||||
{
|
||||
free(text);
|
||||
return;
|
||||
}
|
||||
Sleep(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (textpos+l+1 >= allocsize)
|
||||
{
|
||||
allocsize = textpos+l+1+8192;
|
||||
text=(char*)realloc(text,allocsize);
|
||||
}
|
||||
memcpy(text+textpos,buf,l);
|
||||
textpos+=l;
|
||||
}
|
||||
}
|
||||
if (text) {
|
||||
text[textpos]=0;
|
||||
//fucko: check for case
|
||||
if(strstr(filename,".srt")) decodeSrtFile(text);
|
||||
else if(strstr(filename,".sub")) decodeSubFile(text);
|
||||
free(text);
|
||||
}
|
||||
}
|
||||
delete(file_reader);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SUBTITLES_READER
|
||||
void Subtitles::decodeSrtFile(char *text) {
|
||||
// parse subtitle file (.srt format)
|
||||
char *p=text;
|
||||
|
||||
//for(int i=0;;i++) {
|
||||
while(1) {
|
||||
unsigned int time_start,time_end;
|
||||
|
||||
// parse title nb
|
||||
char *p2=p;
|
||||
while(*p2 && *p2!='\n') p2++;
|
||||
*p2++=0;
|
||||
//if(atoi(p)!=i+1) break;
|
||||
if(atoi(p)<=0) break;
|
||||
|
||||
// parse start time
|
||||
p=p2;
|
||||
while(*p2 && *p2!=' ') p2++;
|
||||
*p2++=0;
|
||||
time_start=getTimeFromSrtText(p);
|
||||
|
||||
// parse "-->"
|
||||
while(*p2 && *p2!=' ') p2++;
|
||||
p2++;
|
||||
|
||||
// parse end time
|
||||
p=p2;
|
||||
while(*p2 && *p2!='\n') p2++;
|
||||
*p2++=0;
|
||||
time_end=getTimeFromSrtText(p);
|
||||
|
||||
// parse text
|
||||
p=p2;
|
||||
while(*p2 && !(*p2=='\r' || *p=='\n')) {
|
||||
while(*p2 && *p2!='\n') p2++;
|
||||
p2++;
|
||||
}
|
||||
*p2++=0;
|
||||
|
||||
//remove trailing CR
|
||||
{
|
||||
int l=strlen(p);
|
||||
if(l) {
|
||||
if(p[l-1]=='\r' || p[l-1]=='\n') p[l-1]=0;
|
||||
}
|
||||
}
|
||||
|
||||
m_subs.put(new SubsItem(time_start,time_end,p));
|
||||
|
||||
if(*p2=='\n') p2++;
|
||||
p=p2;
|
||||
}
|
||||
m_frame_based=0;
|
||||
}
|
||||
|
||||
unsigned int Subtitles::getTimeFromSrtText(const char *text) {
|
||||
int hours,mins,secs,mills;
|
||||
const char *p=text;
|
||||
hours=atoi(p);
|
||||
while(*p && *p!=':') p++;
|
||||
p++;
|
||||
mins=atoi(p);
|
||||
while(*p && *p!=':') p++;
|
||||
p++;
|
||||
secs=atoi(p);
|
||||
while(*p && *p!=',') p++;
|
||||
p++;
|
||||
mills=atoi(p);
|
||||
return mills+(secs*1000)+(mins*60000)+(hours*60*60000);
|
||||
}
|
||||
|
||||
void Subtitles::decodeSubFile(char *text)
|
||||
{
|
||||
char *p=text;
|
||||
while(*p=='{') {
|
||||
int framestart,frameend;
|
||||
p++;
|
||||
char *p2=p;
|
||||
while(*p2 && *p2!='}') p2++;
|
||||
*p2++=0;
|
||||
framestart=atoi(p);
|
||||
|
||||
p2+=1;
|
||||
p=p2;
|
||||
while(*p2 && *p2!='}') p2++;
|
||||
*p2++=0;
|
||||
frameend=atoi(p);
|
||||
|
||||
p=p2;
|
||||
while(*p2 && *p2!='\r' && *p2!='\n') {
|
||||
//replace pipes with CR
|
||||
if(*p2=='|') *p2='\n';
|
||||
p2++;
|
||||
}
|
||||
*p2++=0;
|
||||
|
||||
m_subs.put(new SubsItem(framestart,frameend,p));
|
||||
|
||||
if(*p2=='\n') p2++;
|
||||
p=p2;
|
||||
}
|
||||
m_frame_based=1;
|
||||
}
|
||||
#endif
|
||||
|
||||
SubsItem *Subtitles::getSubtitle(unsigned int time, unsigned int frame)
|
||||
{
|
||||
unsigned int ref=m_frame_based?frame:time;
|
||||
|
||||
//check with lastsub
|
||||
if(m_last_sub!=-1) {
|
||||
SubsItem *item=m_subs.get(m_last_sub);
|
||||
if(ref>=item->timestart && ref<=item->timeend)
|
||||
{
|
||||
item->fontSize=item->origFontSize+m_font_size_mod;
|
||||
return item;
|
||||
}
|
||||
SubsItem *item2=m_subs.get(m_last_sub+1);
|
||||
if(item2) {
|
||||
if(ref>=item->timeend && ref<=item2->timestart) return NULL;
|
||||
if(ref>=item2->timestart && ref<=item2->timeend) {
|
||||
m_last_sub++;
|
||||
item2->fontSize=item2->origFontSize+m_font_size_mod;
|
||||
return item2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int l= (int)m_subs.getlen();
|
||||
for(int i=0;i<l;i++) {
|
||||
SubsItem *item=m_subs.get(i);
|
||||
if(ref<item->timestart) break;
|
||||
if(ref>=item->timestart && ref<=item->timeend) {
|
||||
m_last_sub=i;
|
||||
item->fontSize=item->origFontSize+m_font_size_mod;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
m_last_sub=-1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Subtitles::addSubtitlePacket(SUBTITLE_INFO *sti)
|
||||
{
|
||||
m_frame_based=1; //FUCKO: put this in subsitem struct
|
||||
SubsItem *i=new SubsItem(sti->start_frame,sti->end_frame,sti->utf8_text);
|
||||
i->xPos=sti->xPos;
|
||||
i->yPos=sti->yPos;
|
||||
i->colorBlue=sti->colorBlue;
|
||||
i->colorGreen=sti->colorGreen;
|
||||
i->colorRed=sti->colorRed;
|
||||
i->extraDataSize=sti->extraDataSize;
|
||||
i->origFontSize=sti->fontSize;
|
||||
if(sti->extraDataSize) {
|
||||
i->extraData=malloc(sti->extraDataSize);
|
||||
memcpy((void *)i->extraData,sti->extraData,sti->extraDataSize);
|
||||
}
|
||||
i->muxed_subtitle=1;
|
||||
m_subs.put(i);
|
||||
}
|
62
Src/nsv/nsvplay/subtitles.h
Normal file
62
Src/nsv/nsvplay/subtitles.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef NSVPLAY_SUBTITLES_H
|
||||
#define NSVPLAY_SUBTITLES_H
|
||||
|
||||
#include "main.h"
|
||||
#include "../nsvbs.h"
|
||||
|
||||
class SubsItem {
|
||||
public:
|
||||
SubsItem(unsigned int ptimestart, unsigned int ptimeend, const char *ptext) :
|
||||
timestart(ptimestart) , timeend(ptimeend) {
|
||||
text=_strdup(ptext);
|
||||
xPos=128;
|
||||
yPos=255;
|
||||
colorRed=colorGreen=colorBlue=0xff;
|
||||
extraDataSize=0;
|
||||
extraData=0;
|
||||
muxed_subtitle=0;
|
||||
fontSize=origFontSize=0;
|
||||
}
|
||||
~SubsItem() {
|
||||
free((void*)text);
|
||||
if(extraDataSize) free((void *)extraData);
|
||||
}
|
||||
|
||||
unsigned int timestart;
|
||||
unsigned int timeend;
|
||||
const char *text;
|
||||
|
||||
unsigned char xPos, yPos;
|
||||
unsigned char colorRed, colorGreen, colorBlue;
|
||||
int extraDataSize;
|
||||
const void *extraData;
|
||||
|
||||
int muxed_subtitle; //so we free it when we seek/display
|
||||
|
||||
int fontSize;
|
||||
|
||||
int origFontSize;
|
||||
};
|
||||
|
||||
class Subtitles {
|
||||
public:
|
||||
Subtitles(const char *filename);
|
||||
|
||||
SubsItem *getSubtitle(unsigned int time, unsigned int frame); // time in ms
|
||||
void addSubtitlePacket(SUBTITLE_INFO *sti);
|
||||
|
||||
void setFontSizeModifier(int size) { m_font_size_mod=size; }
|
||||
|
||||
private:
|
||||
void decodeSrtFile(char *text);
|
||||
unsigned int getTimeFromSrtText(const char *text);
|
||||
|
||||
void decodeSubFile(char *text);
|
||||
|
||||
ClassList<SubsItem> m_subs;
|
||||
int m_frame_based;
|
||||
int m_last_sub;
|
||||
int m_font_size_mod;
|
||||
};
|
||||
|
||||
#endif
|
865
Src/nsv/nsvplay/vid_ddraw.cpp
Normal file
865
Src/nsv/nsvplay/vid_ddraw.cpp
Normal file
@ -0,0 +1,865 @@
|
||||
#include "video.h"
|
||||
#include <multimon.h>
|
||||
#include "subtitles.h"
|
||||
|
||||
#define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
|
||||
|
||||
DDrawVideoOutput::DDrawVideoOutput() {
|
||||
lpDD=NULL;
|
||||
lpddsOverlay=NULL;
|
||||
lastresizerect.bottom=0;
|
||||
lastresizerect.top=0;
|
||||
lastresizerect.left=0;
|
||||
lastresizerect.right=0;
|
||||
|
||||
lpddsPrimary=NULL;
|
||||
lpddsClipper=NULL;
|
||||
lpddsSTTemp=NULL;
|
||||
is_fullscreen=0;
|
||||
m_parent=NULL;
|
||||
initing=false;
|
||||
needchange=0;
|
||||
m_palette=NULL;
|
||||
m_lastsubtitle=NULL;
|
||||
sttmp_w=sttmp_h=0;
|
||||
subFont=NULL;
|
||||
m_sub_needremeasure=0;
|
||||
m_fontsize=0;
|
||||
memset(&winRect,0,sizeof(winRect));
|
||||
}
|
||||
|
||||
DDrawVideoOutput::~DDrawVideoOutput() {
|
||||
// LPDIRECTDRAWSURFACE o=lpddsOverlay;
|
||||
lpddsOverlay=NULL;
|
||||
// if(o) o->Release();
|
||||
// if (lpddsSTTemp) lpddsSTTemp->Release();
|
||||
//if(lpddsPrimary) lpddsPrimary->Release();
|
||||
// if(lpddsClipper) lpddsClipper->Release();
|
||||
if (lpDD) lpDD->Release(); // BU added NULL check in response to talkback
|
||||
if(subFont) DeleteObject(subFont);
|
||||
if (is_fullscreen) removeFullScreen();
|
||||
}
|
||||
|
||||
void DDrawVideoOutput::drawSubtitle(SubsItem *item)
|
||||
{
|
||||
m_lastsubtitle=item;
|
||||
m_sub_needremeasure=1;
|
||||
}
|
||||
|
||||
int DDrawVideoOutput::create(VideoOutput *parent, int w, int h, unsigned int ptype, int flipit, double aspectratio) {
|
||||
m_lastsubtitle=NULL;
|
||||
type=ptype;
|
||||
width=w;
|
||||
height=h;
|
||||
flip=flipit;
|
||||
m_parent=parent;
|
||||
|
||||
initing=true;
|
||||
HWND hwnd=parent->getHwnd();
|
||||
|
||||
if (lpDD) lpDD->Release();
|
||||
lpDD=NULL;
|
||||
|
||||
update_monitor_coords(parent);
|
||||
|
||||
if(!m_found_devguid) DirectDrawCreate(NULL,&lpDD,NULL);
|
||||
else DirectDrawCreate(&m_devguid,&lpDD,NULL);
|
||||
|
||||
if(!lpDD) {
|
||||
initing=false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lpDD->SetCooperativeLevel(hwnd,DDSCL_NOWINDOWCHANGES|DDSCL_NORMAL);
|
||||
|
||||
DDSURFACEDESC ddsd;
|
||||
INIT_DIRECTDRAW_STRUCT(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
HRESULT ddrval = lpDD->CreateSurface(&ddsd, &lpddsPrimary, NULL );
|
||||
|
||||
HRESULT v=-1;
|
||||
DDSURFACEDESC DDsd={sizeof(DDsd),};
|
||||
lpddsPrimary->GetSurfaceDesc(&ddsd);
|
||||
DDsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT; //create the surface at screen depth
|
||||
DDsd.dwWidth=w;
|
||||
DDsd.dwHeight=h;
|
||||
DDsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
|
||||
if (parent->vid_ddraw) v=lpDD->CreateSurface(&DDsd, &lpddsOverlay, NULL);
|
||||
if(!parent->vid_ddraw || FAILED(v)) {
|
||||
// fall back to system memory if video mem doesn't work
|
||||
DDsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
|
||||
v=lpDD->CreateSurface(&DDsd, &lpddsOverlay, NULL);
|
||||
}
|
||||
if(FAILED(v)) {
|
||||
// this video card sucks then :)
|
||||
lpddsOverlay=NULL;
|
||||
initing=false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get the depth
|
||||
m_depth=8;
|
||||
INIT_DIRECTDRAW_STRUCT(m_ddpf);
|
||||
if(lpddsOverlay->GetPixelFormat(&m_ddpf)>=0) {
|
||||
m_depth=m_ddpf.dwRGBBitCount;
|
||||
if (m_depth==16 && m_ddpf.dwGBitMask==0x03e0) m_depth=15;
|
||||
}
|
||||
|
||||
lpDD->CreateClipper(0,&lpddsClipper,NULL);
|
||||
lpddsClipper->SetHWnd(0,hwnd);
|
||||
lpddsPrimary->SetClipper(lpddsClipper);
|
||||
initing=false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DDrawVideoOutput::onPaint(HWND hwnd, HDC hdc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DDrawVideoOutput::displayFrame(const char *buf, int size, int time) {
|
||||
DDSURFACEDESC dd={sizeof(dd),};
|
||||
if (m_parent->vid_vsync) lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);
|
||||
HRESULT result;
|
||||
if ((result=lpddsOverlay->Lock(NULL,&dd,DDLOCK_WAIT,NULL)) != DD_OK) {
|
||||
needchange=1;
|
||||
return;
|
||||
}
|
||||
if(type==NSV_MAKETYPE('Y','V','1','2')) {
|
||||
const YV12_PLANES *planes=(YV12_PLANES *)buf;
|
||||
// convert yv12 to rgb
|
||||
int bytes = m_depth >> 3;
|
||||
if(m_depth==15) bytes=2;
|
||||
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*)dd.lpSurface;
|
||||
const int rvScale = 91881;
|
||||
const int guScale = -22553;
|
||||
const int gvScale = -46801;
|
||||
const int buScale = 116129;
|
||||
const int yScale = 65536;
|
||||
int addOut=dd.lPitch*2-width*bytes;
|
||||
int yrb=planes->y.rowBytes;
|
||||
int addL=dd.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+=(dd.lPitch)*(height-1);
|
||||
addOut=-dd.lPitch*2 - width*bytes;
|
||||
addL=-addL;
|
||||
}
|
||||
|
||||
for (j = 0; j <= height - 2; j += 2) {
|
||||
for (i = 0; i <= width - 2; i += 2) {
|
||||
y00 = *pY;
|
||||
y01 = *(pY + 1);
|
||||
y10 = *(pY + yrb);
|
||||
y11 = *(pY + yrb + 1);
|
||||
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;
|
||||
|
||||
switch(m_depth) {
|
||||
case 15:
|
||||
{
|
||||
unsigned short *rgb=(unsigned short *)pOut;
|
||||
rgb[0]=((LIMIT(r+y00)>>3)<<10)|((LIMIT(g+y00)>>3)<<5)|(LIMIT(b+y00)>>3);
|
||||
rgb[1]=((LIMIT(r+y01)>>3)<<10)|((LIMIT(g+y01)>>3)<<5)|(LIMIT(b+y01)>>3);
|
||||
rgb+=addL/2;
|
||||
rgb[0]=((LIMIT(r+y10)>>3)<<10)|((LIMIT(g+y10)>>3)<<5)|(LIMIT(b+y10)>>3);
|
||||
rgb[1]=((LIMIT(r+y11)>>3)<<10)|((LIMIT(g+y11)>>3)<<5)|(LIMIT(b+y11)>>3);
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
{
|
||||
unsigned short *rgb=(unsigned short *)pOut;
|
||||
rgb[0]=((LIMIT(r+y00)>>3)<<11)|((LIMIT(g+y00)>>2)<<5)|(LIMIT(b+y00)>>3);
|
||||
rgb[1]=((LIMIT(r+y01)>>3)<<11)|((LIMIT(g+y01)>>2)<<5)|(LIMIT(b+y01)>>3);
|
||||
rgb+=addL/2;
|
||||
rgb[0]=((LIMIT(r+y10)>>3)<<11)|((LIMIT(g+y10)>>2)<<5)|(LIMIT(b+y10)>>3);
|
||||
rgb[1]=((LIMIT(r+y11)>>3)<<11)|((LIMIT(g+y11)>>2)<<5)|(LIMIT(b+y11)>>3);
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
{
|
||||
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[3] = LIMIT(b+y01); rgb[4] = LIMIT(g+y01); rgb[5] = 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[3] = LIMIT(b+y11); rgb[4] = LIMIT(g+y11); rgb[5] = LIMIT(r+y11);
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
{
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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==NSV_MAKETYPE('R','G','3','2')) {
|
||||
//FUCKO: do we need to support 8bits depth?
|
||||
switch(m_depth) {
|
||||
case 15:
|
||||
{ // convert RGB32 -> RGB16 (555)
|
||||
const char *a=buf;
|
||||
char *b=(char *)dd.lpSurface;
|
||||
int l=width*4,l2=dd.lPitch;
|
||||
int ladj=l;
|
||||
if (flip) { a+=l*(height-1); ladj=-ladj; }
|
||||
for(int i=0;i<height;i++) {
|
||||
short *dest=(short *)b;
|
||||
int *src=(int *)a;
|
||||
for(int j=0;j<width;j++) {
|
||||
int c=*(src++);
|
||||
int r=c>>16;
|
||||
int g=(c>>8) & 0xff;
|
||||
int b=(c) & 0xff;
|
||||
*(dest++)=((r>>3)<<10)|((g>>3)<<5)|(b>>3);
|
||||
}
|
||||
a+=ladj; b+=l2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
{ // convert RGB32 -> RGB16
|
||||
//FUCKO: this assumes 565
|
||||
const char *a=buf;
|
||||
char *b=(char *)dd.lpSurface;
|
||||
int l=width*4,l2=dd.lPitch;
|
||||
int ladj=l;
|
||||
if (flip) { a+=l*(height-1); ladj=-ladj; }
|
||||
for(int i=0;i<height;i++) {
|
||||
short *dest=(short *)b;
|
||||
int *src=(int *)a;
|
||||
for(int j=0;j<width;j++) {
|
||||
//FUCKO: optimize here
|
||||
int c=*(src++);
|
||||
int r=c>>16;
|
||||
int g=(c>>8) & 0xff;
|
||||
int b=(c) & 0xff;
|
||||
*(dest++)=((r>>3)<<11)|((g>>2)<<5)|(b>>3);
|
||||
}
|
||||
a+=ladj; b+=l2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
{ // convert RGB32 -> RGB24
|
||||
const char *a=buf;
|
||||
char *b=(char *)dd.lpSurface;
|
||||
int l=width*4,l2=dd.lPitch;
|
||||
int ladj=l;
|
||||
if (flip) { a+=l*(height-1); ladj=-ladj; }
|
||||
for(int i=0;i<height;i++) {
|
||||
char *dest=(char *)b;
|
||||
int *src=(int *)a;
|
||||
for(int j=0;j<width;j++) {
|
||||
//FUCKO: optimize here
|
||||
int c=*(src++);
|
||||
int r=c>>16;
|
||||
int g=(c>>8) & 0xff;
|
||||
int b=(c) & 0xff;
|
||||
*dest++=b;
|
||||
*dest++=g;
|
||||
*dest++=r;
|
||||
}
|
||||
a+=ladj; b+=l2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
{ // straight RGB32 copy
|
||||
const char *a=buf;
|
||||
char *b=(char *)dd.lpSurface;
|
||||
int l=width*4,l2=dd.lPitch;
|
||||
int ladj=l;
|
||||
if (flip) { a+=l*(height-1); ladj=-ladj; }
|
||||
for(int i=0;i<height;i++) {
|
||||
memcpy(b,a,l);
|
||||
a+=ladj; b+=l2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if(type==NSV_MAKETYPE('Y','U','Y','2') || type==NSV_MAKETYPE('U','Y','V','Y')) {
|
||||
const char *a=buf;
|
||||
char *b=(char *)dd.lpSurface;
|
||||
int l=width*2,l2=dd.lPitch;
|
||||
if(flip) {
|
||||
b+=(height-1)*l2;
|
||||
l2=-l2;
|
||||
}
|
||||
switch(m_depth) {
|
||||
case 15:
|
||||
{
|
||||
// yuy2->rgb16 (555) conversion
|
||||
unsigned char *src=(unsigned char *)buf;
|
||||
unsigned short *dst=(unsigned short *)dd.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=dd.lPitch/2-width;
|
||||
|
||||
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;
|
||||
|
||||
unsigned char b=LIMIT(yy + ub );
|
||||
unsigned char g=LIMIT(yy - ug - vg);
|
||||
unsigned char r=LIMIT(yy + vr);
|
||||
*(dst++)=((r>>3)<<10)|((g>>3)<<5)|(b>>3);
|
||||
|
||||
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 */
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
{
|
||||
// yuy2->rgb16 conversion
|
||||
//FUCKO: only supports 565
|
||||
unsigned char *src=(unsigned char *)buf;
|
||||
unsigned short *dst=(unsigned short *)dd.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=dd.lPitch/2-width;
|
||||
|
||||
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;
|
||||
|
||||
unsigned char b=LIMIT(yy + ub );
|
||||
unsigned char g=LIMIT(yy - ug - vg);
|
||||
unsigned char r=LIMIT(yy + vr);
|
||||
*(dst++)=((r>>3)<<11)|((g>>2)<<5)|(b>>3);
|
||||
|
||||
py += 2;
|
||||
if ( (col & 1) ) {
|
||||
pu += 4; // skip yvy every second y
|
||||
pv += 4; // skip yuy every second y
|
||||
}
|
||||
} // ..for col
|
||||
dst+=pitchadd;
|
||||
} /* ..for line */ }
|
||||
break;
|
||||
case 24:
|
||||
{
|
||||
// yuy2->rgb24 conversion
|
||||
unsigned char *src=(unsigned char *)buf;
|
||||
unsigned char *dst=(unsigned char *)dd.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=dd.lPitch-(width*3);
|
||||
|
||||
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 );
|
||||
*(dst++)=LIMIT(yy - ug - vg);
|
||||
*(dst++)=LIMIT(yy + vr);
|
||||
|
||||
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 */ }
|
||||
break;
|
||||
case 32:
|
||||
{
|
||||
// yuy2->rgb32 conversion
|
||||
unsigned char *src=(unsigned char *)buf;
|
||||
unsigned char *dst=(unsigned char *)dd.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=dd.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 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if(type==NSV_MAKETYPE('R','G','2','4')) {
|
||||
//FUCKO: only ->RGB32 conversion supported
|
||||
switch(m_depth) {
|
||||
case 32:
|
||||
{
|
||||
const char *a=buf;
|
||||
char *b=(char *)dd.lpSurface;
|
||||
int l=width,l2=dd.lPitch;
|
||||
int ladj=l*3;
|
||||
if (flip) { a+=(l*3)*(height-1); ladj=-(ladj+l*3); }
|
||||
l2-=l*4;
|
||||
for(int i=0;i<height;i++) {
|
||||
//memcpy(b,a,l);
|
||||
for(int j=0;j<l;j++) {
|
||||
b[0]=a[0];
|
||||
b[1]=a[1];
|
||||
b[2]=a[2];
|
||||
b+=4; a+=3;
|
||||
}
|
||||
a+=ladj; b+=l2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if(type==NSV_MAKETYPE('R','G','B','8') && m_palette) {
|
||||
unsigned char *d=(unsigned char *)dd.lpSurface;
|
||||
int pitch=dd.lPitch;
|
||||
unsigned char *src=(unsigned char *)buf;
|
||||
int newwidth=(width+3)&0xfffc;
|
||||
src+=newwidth*height-1;
|
||||
for(int j=0;j<height;j++) {
|
||||
switch(m_depth) {
|
||||
case 15:
|
||||
case 16:
|
||||
{
|
||||
unsigned short *dest=(unsigned short *)d;
|
||||
for(int i=0;i<newwidth;i++) {
|
||||
unsigned char c=src[-newwidth+1+i];
|
||||
RGBQUAD *rgb=&m_palette[c];
|
||||
switch(m_depth) {
|
||||
case 15: *(dest++)=((rgb->rgbRed>>3)<<10)|((rgb->rgbGreen>>3)<<5)|(rgb->rgbBlue>>3); break;
|
||||
case 16: *(dest++)=((rgb->rgbRed>>3)<<11)|((rgb->rgbGreen>>2)<<5)|(rgb->rgbBlue>>3); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
{
|
||||
unsigned char *dest=d;
|
||||
for(int i=0;i<newwidth;i++) {
|
||||
unsigned char c=src[-newwidth+1+i];
|
||||
RGBQUAD *rgb=&m_palette[c];
|
||||
*dest++=rgb->rgbBlue;
|
||||
*dest++=rgb->rgbGreen;
|
||||
*dest++=rgb->rgbRed;
|
||||
if(m_depth==32) dest++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
d+=pitch;
|
||||
src-=newwidth;
|
||||
}
|
||||
}
|
||||
|
||||
lpddsOverlay->Unlock(&dd);
|
||||
|
||||
|
||||
RECT r;
|
||||
HWND hwnd=m_parent->getHwnd();
|
||||
if (!IsWindow(hwnd)) return;
|
||||
|
||||
if(GetParent(hwnd)) hwnd=GetParent(hwnd);
|
||||
|
||||
GetClientRect(hwnd,&r);
|
||||
RECT fullr=r;
|
||||
m_parent->adjustAspect(r);
|
||||
if (r.left != lastresizerect.left || r.right != lastresizerect.right || r.top != lastresizerect.top ||
|
||||
r.bottom != lastresizerect.bottom)
|
||||
{
|
||||
if (r.left != 0)
|
||||
{
|
||||
RECT tmp={0,0,r.left,fullr.bottom};
|
||||
InvalidateRect(hwnd,&tmp,TRUE);
|
||||
}
|
||||
|
||||
if (r.right != fullr.right)
|
||||
{
|
||||
RECT tmp={r.right,0,fullr.right,fullr.bottom};
|
||||
InvalidateRect(hwnd,&tmp,TRUE);
|
||||
}
|
||||
if (r.top != 0)
|
||||
{
|
||||
RECT tmp={r.left,0,r.right,r.top};
|
||||
InvalidateRect(hwnd,&tmp,TRUE);
|
||||
}
|
||||
if (r.bottom != fullr.bottom)
|
||||
{
|
||||
RECT tmp={r.left,r.bottom,r.right,fullr.bottom};
|
||||
InvalidateRect(hwnd,&tmp,TRUE);
|
||||
}
|
||||
|
||||
lastresizerect=r;
|
||||
}
|
||||
|
||||
ClientToScreen(hwnd,(LPPOINT)&r);
|
||||
ClientToScreen(hwnd,((LPPOINT)&r) + 1);
|
||||
|
||||
// transform coords from windows desktop coords (where 0,0==upper-left corner of box encompassing all monitors)
|
||||
// to the coords for the monitor we're displaying on:
|
||||
r.left-=m_mon_x;
|
||||
r.right-=m_mon_x;
|
||||
r.top-=m_mon_y;
|
||||
r.bottom-=m_mon_y;
|
||||
|
||||
HDC hdc = NULL;
|
||||
HDC inhdc = NULL;
|
||||
|
||||
RECT srcrect;
|
||||
RECT *pSrcRect = NULL;
|
||||
|
||||
if (m_parent->osdShowing() && m_parent->osdReady())
|
||||
{
|
||||
// squish image upward to make room for the OSD.
|
||||
int vert_margin = ((fullr.bottom-fullr.top) - (r.bottom-r.top)) / 2;
|
||||
int pixels_to_clip = max(0, m_parent->getOSDbarHeight() - vert_margin);
|
||||
|
||||
// adjust source rectangle:
|
||||
int src_y0 = (int)(height*pixels_to_clip/(float)(r.bottom-r.top) + 0.5f);
|
||||
int src_y1 = height - src_y0;
|
||||
SetRect(&srcrect, 0, SHOW_STREAM_TITLE_AT_TOP ? src_y0 : 0, width, src_y1);
|
||||
pSrcRect = &srcrect;
|
||||
|
||||
// adjust destination rectangle:
|
||||
r.bottom -= pixels_to_clip;
|
||||
#if (SHOW_STREAM_TITLE_AT_TOP)
|
||||
r.top += pixels_to_clip;
|
||||
#endif
|
||||
}
|
||||
|
||||
int needst=0;
|
||||
|
||||
|
||||
SubsItem *mlst=m_lastsubtitle;
|
||||
if (mlst)
|
||||
{
|
||||
int curw=r.right-r.left, curh=r.bottom-r.top;
|
||||
if (!lpddsSTTemp || sttmp_w != curw || sttmp_h != curh)
|
||||
{
|
||||
if (lpddsSTTemp) lpddsSTTemp->Release();
|
||||
lpddsSTTemp=0;
|
||||
|
||||
HRESULT v=-1;
|
||||
DDSURFACEDESC DDsd={sizeof(DDsd),};
|
||||
DDSURFACEDESC ddsd;
|
||||
INIT_DIRECTDRAW_STRUCT(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
lpddsPrimary->GetSurfaceDesc(&ddsd);
|
||||
DDsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT; //create the surface at screen depth
|
||||
DDsd.dwWidth=sttmp_w=curw;
|
||||
DDsd.dwHeight=sttmp_h=curh;
|
||||
DDsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
|
||||
if (m_parent->vid_ddraw) v=lpDD->CreateSurface(&DDsd, &lpddsSTTemp, NULL);
|
||||
if (!m_parent->vid_ddraw || FAILED(v)) {
|
||||
// fall back to system memory if video mem doesn't work
|
||||
DDsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
|
||||
v=lpDD->CreateSurface(&DDsd, &lpddsSTTemp, NULL);
|
||||
}
|
||||
m_sub_needremeasure=1;
|
||||
}
|
||||
if (lpddsSTTemp) needst=1;
|
||||
}
|
||||
|
||||
if (needst)
|
||||
{
|
||||
HDC tmpdc=NULL;
|
||||
if (!m_parent->vid_ddraw || lpddsSTTemp->Blt(NULL,lpddsOverlay,NULL,DDBLT_WAIT,0) != DD_OK) {
|
||||
// as a last resort, BitBlt().
|
||||
HDC tmpdc2;
|
||||
if (lpddsOverlay->GetDC(&tmpdc2)==DD_OK) {
|
||||
if (lpddsSTTemp->GetDC(&tmpdc)==DD_OK) {
|
||||
BitBlt(tmpdc,0,0,sttmp_w,sttmp_h,tmpdc2,0,0,SRCCOPY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpdc||lpddsSTTemp->GetDC(&tmpdc)==DD_OK)
|
||||
{
|
||||
int m_lastsubxp=mlst->xPos;
|
||||
int m_lastsubyp=mlst->yPos;
|
||||
|
||||
RECT oldwinRect=winRect;
|
||||
GetClientRect(hwnd,&winRect);
|
||||
if(!subFont || ((winRect.bottom-winRect.top)!=(oldwinRect.bottom-oldwinRect.top)) || m_fontsize!=mlst->fontSize) {
|
||||
if(subFont) DeleteObject(subFont);
|
||||
m_fontsize=mlst->fontSize;
|
||||
subFont=CreateFont(14+m_fontsize+18*(winRect.bottom-winRect.top)/768,0,0,0,FW_SEMIBOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_OUTLINE_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH|FF_DONTCARE,"Arial");
|
||||
}
|
||||
|
||||
HWND hwnd=m_parent->getHwnd();
|
||||
HGDIOBJ oldobj=SelectObject(tmpdc,subFont);
|
||||
|
||||
int centerflags=0;
|
||||
if (m_lastsubxp < 127) centerflags |= DT_LEFT;
|
||||
else if (m_lastsubxp > 127) centerflags |= DT_RIGHT;
|
||||
else centerflags |= DT_CENTER;
|
||||
|
||||
if (m_lastsubyp < 127) centerflags |= DT_TOP;
|
||||
else if (m_lastsubyp > 127) centerflags |= DT_BOTTOM;
|
||||
|
||||
if (m_sub_needremeasure)
|
||||
{
|
||||
subRect=r;
|
||||
subRect.bottom-=subRect.top;
|
||||
subRect.right -=subRect.left;
|
||||
subRect.top=subRect.left=0;
|
||||
|
||||
SIZE s;
|
||||
GetTextExtentPoint32(tmpdc,mlst->text,strlen(mlst->text),&s);
|
||||
|
||||
// calcul for multiline text
|
||||
const char *p=mlst->text;
|
||||
int n=0;
|
||||
while(*p!=0) if(*p++=='\n') n++;
|
||||
if(n) s.cy*=(n+1);
|
||||
|
||||
if (m_lastsubxp > 127) // towards the right
|
||||
{
|
||||
subRect.right -= ((subRect.right-subRect.left) * (255-m_lastsubxp)) / 256;
|
||||
}
|
||||
else if (m_lastsubxp < 127)
|
||||
{
|
||||
subRect.left += ((subRect.right-subRect.left) * m_lastsubxp) / 256;
|
||||
}
|
||||
|
||||
subRect.top += ((subRect.bottom-s.cy-subRect.top) * m_lastsubyp)/255;
|
||||
|
||||
subRect.bottom=subRect.top + s.cy;
|
||||
}
|
||||
|
||||
SetBkMode(tmpdc,TRANSPARENT);
|
||||
|
||||
// draw outline
|
||||
SetTextColor(tmpdc,RGB(0,0,0));
|
||||
int y=1;
|
||||
int x=1;
|
||||
RECT r2={subRect.left+x,subRect.top+y,subRect.right+x,subRect.bottom+y};
|
||||
DrawText(tmpdc,mlst->text,-1,&r2,centerflags|DT_NOCLIP|DT_NOPREFIX);
|
||||
// draw text
|
||||
SetTextColor(tmpdc,RGB(mlst->colorRed,mlst->colorGreen,mlst->colorBlue));
|
||||
DrawText(tmpdc,mlst->text,-1,&subRect,centerflags|DT_NOCLIP|DT_NOPREFIX);
|
||||
SelectObject(tmpdc,oldobj);
|
||||
lpddsSTTemp->ReleaseDC(tmpdc);
|
||||
}
|
||||
if (!m_parent->vid_ddraw || lpddsPrimary->Blt(&r,lpddsSTTemp,pSrcRect,DDBLT_WAIT,0) != DD_OK) {
|
||||
// as a last resort, BitBlt().
|
||||
if (lpddsSTTemp->GetDC(&inhdc)==DD_OK) {
|
||||
if (lpddsPrimary->GetDC(&hdc)==DD_OK) {
|
||||
int src_w = width;
|
||||
int src_h = pSrcRect ? (pSrcRect->bottom - pSrcRect->top) : height;
|
||||
if (r.right-r.left == src_w && r.bottom-r.top == src_h)
|
||||
BitBlt(hdc,r.left,r.top,r.right-r.left,r.bottom-r.top,inhdc,0,0,SRCCOPY);
|
||||
else
|
||||
StretchBlt(hdc,r.left,r.top,r.right-r.left,r.bottom-r.top,inhdc,0,0,src_w,src_h,SRCCOPY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_parent->vid_ddraw || lpddsPrimary->Blt(&r,lpddsOverlay,pSrcRect,DDBLT_WAIT,0) != DD_OK) {
|
||||
// as a last resort, BitBlt().
|
||||
if (lpddsOverlay->GetDC(&inhdc)==DD_OK) {
|
||||
if (lpddsPrimary->GetDC(&hdc)==DD_OK) {
|
||||
int src_w = width;
|
||||
int src_h = pSrcRect ? (pSrcRect->bottom - pSrcRect->top) : height;
|
||||
if (r.right-r.left == src_w && r.bottom-r.top == src_h)
|
||||
BitBlt(hdc,r.left,r.top,r.right-r.left,r.bottom-r.top,inhdc,0,0,SRCCOPY);
|
||||
else
|
||||
StretchBlt(hdc,r.left,r.top,r.right-r.left,r.bottom-r.top,inhdc,0,0,src_w,src_h,SRCCOPY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 //faster style
|
||||
if (m_parent->osdShowing())
|
||||
{
|
||||
if (hdc || lpddsPrimary->GetDC(&hdc)==DD_OK)
|
||||
m_parent->drawOSD(hdc, &r);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hdc) { lpddsPrimary->ReleaseDC(hdc); hdc = NULL; }
|
||||
if (inhdc) { lpddsOverlay->ReleaseDC(inhdc); inhdc = NULL; }
|
||||
|
||||
#if 1 // safer style
|
||||
if (m_parent->osdShowing())
|
||||
{
|
||||
HWND h=m_parent->getHwnd();
|
||||
hdc=GetDC(h);
|
||||
m_parent->drawOSD(hdc, &r);
|
||||
ReleaseDC(h,hdc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DDrawVideoOutput::goFullScreen() {
|
||||
}
|
||||
|
||||
void DDrawVideoOutput::removeFullScreen() {
|
||||
}
|
||||
|
||||
void DDrawVideoOutput::timerCallback() {
|
||||
}
|
||||
|
||||
int DDrawVideoOutput::showOSD() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DDrawVideoOutput::hideOSD() {
|
||||
// repaint the client area, to black, where there is no video
|
||||
// (otherwise the OSD might be left painted there)
|
||||
|
||||
RECT r;
|
||||
HWND hwnd=m_parent->getHwnd();
|
||||
if(GetParent(hwnd)) hwnd=GetParent(hwnd);
|
||||
GetClientRect(hwnd,&r);
|
||||
|
||||
HDC hdc = GetDC(hwnd);
|
||||
if (hdc) {
|
||||
HGDIOBJ oldobj1=SelectObject(hdc,CreateSolidBrush(RGB(0,0,0)));
|
||||
HGDIOBJ oldobj2=SelectObject(hdc,CreatePen(PS_SOLID,0,RGB(0,0,0)));
|
||||
int margin = ((r.bottom - r.top) - (lastresizerect.bottom - lastresizerect.top) + 1) / 2;
|
||||
Rectangle(hdc,r.left,r.top,r.right,r.top + margin);
|
||||
Rectangle(hdc,r.left,r.bottom - margin,r.right,r.bottom);
|
||||
margin = ((r.right - r.left) - (lastresizerect.right - lastresizerect.left) + 1) / 2;
|
||||
Rectangle(hdc,r.left,r.top,r.left + margin,r.bottom);
|
||||
Rectangle(hdc,r.right - margin,r.top,r.right,r.bottom);
|
||||
DeleteObject(SelectObject(hdc,oldobj2));
|
||||
DeleteObject(SelectObject(hdc,oldobj1));
|
||||
|
||||
ReleaseDC(hwnd, hdc);
|
||||
}
|
||||
}
|
||||
|
||||
void DDrawVideoOutput::resetSubtitle()
|
||||
{
|
||||
m_lastsubtitle=0;
|
||||
}
|
63
Src/nsv/nsvplay/vid_ddraw.h
Normal file
63
Src/nsv/nsvplay/vid_ddraw.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef _VIDEO_DDRAW_H
|
||||
#define _VIDEO_DDRAW_H
|
||||
|
||||
#include <ddraw.h>
|
||||
#include "video.h"
|
||||
|
||||
class SubsItem;
|
||||
|
||||
class DDrawVideoOutput : public VideoOutputChild {
|
||||
public:
|
||||
DDrawVideoOutput();
|
||||
virtual ~DDrawVideoOutput();
|
||||
|
||||
int create(VideoOutput *parent, int w, int h, unsigned int type, int flipit, double aspectratio); //return 1 if ok
|
||||
int needChange() { return needchange; }
|
||||
|
||||
int onPaint(HWND hwnd, HDC hdc);
|
||||
void displayFrame(const char *buf, int size, int time);
|
||||
|
||||
void goFullScreen();
|
||||
void removeFullScreen();
|
||||
|
||||
void timerCallback();
|
||||
|
||||
void setPalette(RGBQUAD *pal) { m_palette=pal; }
|
||||
|
||||
int showOSD();
|
||||
void hideOSD();
|
||||
|
||||
void drawSubtitle(SubsItem *item);
|
||||
void resetSubtitle();
|
||||
|
||||
private:
|
||||
int width, height, flip;
|
||||
int needchange;
|
||||
unsigned int type;
|
||||
VideoOutput *m_parent;
|
||||
LPDIRECTDRAW lpDD;
|
||||
LPDIRECTDRAWSURFACE lpddsOverlay, lpddsPrimary, lpddsSTTemp;
|
||||
int sttmp_w, sttmp_h;
|
||||
DDCAPS capsDrv;
|
||||
unsigned int uDestSizeAlign, uSrcSizeAlign;
|
||||
DWORD dwUpdateFlags;
|
||||
RECT rs,rd;
|
||||
RECT lastresizerect;
|
||||
|
||||
bool initing;
|
||||
int is_fullscreen;
|
||||
|
||||
LPDIRECTDRAWCLIPPER lpddsClipper;
|
||||
DDPIXELFORMAT m_ddpf;
|
||||
int m_depth;
|
||||
RGBQUAD *m_palette;
|
||||
|
||||
HFONT subFont;
|
||||
RECT subRect;
|
||||
SubsItem *m_lastsubtitle;
|
||||
int m_sub_needremeasure;
|
||||
RECT winRect;
|
||||
int m_fontsize;
|
||||
};
|
||||
|
||||
#endif
|
654
Src/nsv/nsvplay/vid_overlay.cpp
Normal file
654
Src/nsv/nsvplay/vid_overlay.cpp
Normal file
@ -0,0 +1,654 @@
|
||||
#include "video.h"
|
||||
#include <multimon.h>
|
||||
#include "subtitles.h"
|
||||
|
||||
#define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
|
||||
#define OV_COL_R 16
|
||||
#define OV_COL_G 0
|
||||
#define OV_COL_B 16
|
||||
|
||||
OverlayVideoOutput::OverlayVideoOutput() {
|
||||
lpDD=NULL;
|
||||
lpddsOverlay=NULL;
|
||||
lpddsPrimary=NULL;
|
||||
is_fullscreen=0;
|
||||
yuy2_output=uyvy_output=0;
|
||||
m_parent=NULL;
|
||||
initing=false;
|
||||
needchange=0;
|
||||
memset(&m_oldrd,0,sizeof(m_oldrd));
|
||||
memset(&winRect,0,sizeof(winRect));
|
||||
subFont=NULL;
|
||||
m_fontsize=0;
|
||||
resetSubtitle();
|
||||
}
|
||||
|
||||
OverlayVideoOutput::~OverlayVideoOutput() {
|
||||
if(is_fullscreen) removeFullScreen();
|
||||
LPDIRECTDRAWSURFACE o=lpddsOverlay;
|
||||
lpddsOverlay=NULL;
|
||||
if(o) o->Release();
|
||||
if(lpddsPrimary) lpddsPrimary->Release();
|
||||
if (lpDD) lpDD->Release(); // BU added NULL check in response to talkback
|
||||
if(subFont) DeleteObject(subFont);
|
||||
}
|
||||
|
||||
static DWORD DD_ColorMatch(LPDIRECTDRAWSURFACE pdds, COLORREF rgb)
|
||||
{
|
||||
COLORREF rgbT;
|
||||
HDC hdc;
|
||||
DWORD dw = CLR_INVALID;
|
||||
DDSURFACEDESC ddsd;
|
||||
HRESULT hres;
|
||||
|
||||
//
|
||||
// use GDI SetPixel to color match for us
|
||||
//
|
||||
if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
|
||||
{
|
||||
rgbT = GetPixel(hdc, 0, 0); // save current pixel value
|
||||
SetPixel(hdc, 0, 0, rgb); // set our value
|
||||
pdds->ReleaseDC(hdc);
|
||||
}
|
||||
|
||||
//
|
||||
// now lock the surface so we can read back the converted color
|
||||
//
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) ==
|
||||
DDERR_WASSTILLDRAWING)
|
||||
;
|
||||
|
||||
if (hres == DD_OK)
|
||||
{
|
||||
dw = *(DWORD *)ddsd.lpSurface; // get DWORD
|
||||
if(ddsd.ddpfPixelFormat.dwRGBBitCount<32)
|
||||
dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; // mask it to bpp
|
||||
pdds->Unlock(NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// now put the color that was there back.
|
||||
//
|
||||
if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
|
||||
{
|
||||
SetPixel(hdc, 0, 0, rgbT);
|
||||
pdds->ReleaseDC(hdc);
|
||||
}
|
||||
|
||||
return dw;
|
||||
}
|
||||
|
||||
int OverlayVideoOutput::create(VideoOutput *parent, int w, int h, unsigned int ptype, int flipit, double aspectratio) {
|
||||
type=ptype;
|
||||
width=w;
|
||||
height=h;
|
||||
flip=flipit;
|
||||
m_parent=parent;
|
||||
|
||||
initing=true;
|
||||
HWND hwnd=parent->getHwnd();
|
||||
|
||||
if (lpDD) lpDD->Release();
|
||||
lpDD=NULL;
|
||||
|
||||
update_monitor_coords(parent);
|
||||
|
||||
if(!m_found_devguid) DirectDrawCreate(NULL,&lpDD,NULL);
|
||||
else DirectDrawCreate(&m_devguid,&lpDD,NULL);
|
||||
|
||||
if(!lpDD) {
|
||||
initing=false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lpDD->SetCooperativeLevel(hwnd,DDSCL_NOWINDOWCHANGES|DDSCL_NORMAL);
|
||||
|
||||
DDSURFACEDESC ddsd;
|
||||
INIT_DIRECTDRAW_STRUCT(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
HRESULT ddrval = lpDD->CreateSurface(&ddsd, &lpddsPrimary, NULL );
|
||||
|
||||
// init overlay
|
||||
DDSURFACEDESC ddsdOverlay;
|
||||
INIT_DIRECTDRAW_STRUCT(ddsdOverlay);
|
||||
ddsdOverlay.ddsCaps.dwCaps=DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
|
||||
ddsdOverlay.dwFlags= DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH;
|
||||
ddsdOverlay.dwWidth=w;
|
||||
ddsdOverlay.dwHeight=h;
|
||||
ddsdOverlay.lPitch=w*4;
|
||||
ddsdOverlay.dwBackBufferCount=0;
|
||||
DDPIXELFORMAT pf[]=
|
||||
{
|
||||
{sizeof(DDPIXELFORMAT),DDPF_FOURCC,MAKEFOURCC('Y','U','Y','2'),0,0,0,0,0},
|
||||
{sizeof(DDPIXELFORMAT), DDPF_FOURCC,MAKEFOURCC('U','Y','V','Y'),0,0,0,0,0}, // UYVY
|
||||
{sizeof(DDPIXELFORMAT),DDPF_FOURCC,MAKEFOURCC('Y','V','1','2'),0,0,0,0,0},
|
||||
};
|
||||
int tab[5];
|
||||
if(type==NSV_MAKETYPE('Y','U','Y','2')) {
|
||||
tab[0]=0; // default is YUY2
|
||||
tab[1]=1;
|
||||
tab[2]=-1;
|
||||
} else if(type==NSV_MAKETYPE('U','Y','V','Y')) {
|
||||
tab[0]=1; // make UYVY default
|
||||
tab[1]=0;
|
||||
tab[2]=-1;
|
||||
} else if(type==NSV_MAKETYPE('Y','V','1','2')) {
|
||||
/*tab[0]=2;
|
||||
tab[1]=0;
|
||||
tab[2]=1;
|
||||
tab[3]=-1;*/
|
||||
//CT> Make YUY2 default too, cause YV12 is borked on some ATI cards/drivers :(
|
||||
tab[0]=0;
|
||||
tab[1]=1;
|
||||
tab[2]=-1;
|
||||
} else {
|
||||
tab[0]=-1; // default is RGB
|
||||
}
|
||||
|
||||
int x=4096;
|
||||
HRESULT v=-1;
|
||||
for (x = 0; x < sizeof(tab)/sizeof(tab[0]) && tab[x]>=0; x ++) {
|
||||
ddsdOverlay.ddpfPixelFormat=pf[tab[x]];
|
||||
v=lpDD->CreateSurface(&ddsdOverlay, &lpddsOverlay, NULL);
|
||||
if (!FAILED(v)) break;
|
||||
}
|
||||
if(FAILED(v)||x>=sizeof(tab)/sizeof(tab[0])||tab[x]<0) {
|
||||
initing=false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
yuy2_output = (tab[x] == 0);
|
||||
uyvy_output = (tab[x] == 1);
|
||||
|
||||
INIT_DIRECTDRAW_STRUCT(capsDrv);
|
||||
ddrval = lpDD->GetCaps(&capsDrv, NULL);
|
||||
|
||||
uDestSizeAlign = capsDrv.dwAlignSizeDest;
|
||||
uSrcSizeAlign = capsDrv.dwAlignSizeSrc;
|
||||
|
||||
dwUpdateFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
|
||||
|
||||
DEVMODE d;
|
||||
d.dmSize=sizeof(d);
|
||||
d.dmDriverExtra=0;
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &d);
|
||||
|
||||
int rv=OV_COL_R, gv=OV_COL_G, bv=OV_COL_B;
|
||||
|
||||
INIT_DIRECTDRAW_STRUCT(ovfx);
|
||||
ovfx.dwDDFX=0;
|
||||
switch(d.dmBitsPerPel) {
|
||||
case 16:
|
||||
ovfx.dckDestColorkey.dwColorSpaceLowValue=((rv>>3) << 11) | ((gv>>2) << 5) | (bv>>3);
|
||||
break;
|
||||
case 15:
|
||||
ovfx.dckDestColorkey.dwColorSpaceLowValue=((rv>>3) << 10) | ((gv>>3) << 5) | (bv>>3);
|
||||
break;
|
||||
case 24: case 32:
|
||||
ovfx.dckDestColorkey.dwColorSpaceLowValue=(rv << 16) | (gv << 8) | bv;
|
||||
break;
|
||||
}
|
||||
|
||||
//try to get the correct bit depth thru directdraw (for fucked up 16 bits displays for ie.)
|
||||
{
|
||||
DDSURFACEDESC DDsd={sizeof(DDsd),};
|
||||
lpddsPrimary->GetSurfaceDesc(&ddsd);
|
||||
DDsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT; //create the surface at screen depth
|
||||
DDsd.dwWidth=8;
|
||||
DDsd.dwHeight=8;
|
||||
DDsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
|
||||
LPDIRECTDRAWSURFACE tempsurf;
|
||||
if(lpDD->CreateSurface(&DDsd, &tempsurf, NULL)==DD_OK)
|
||||
{
|
||||
int res=DD_ColorMatch(tempsurf, RGB(rv,gv,bv));
|
||||
if(res!=CLR_INVALID) ovfx.dckDestColorkey.dwColorSpaceLowValue=res;
|
||||
tempsurf->Release();
|
||||
}
|
||||
}
|
||||
|
||||
ovfx.dckDestColorkey.dwColorSpaceHighValue=ovfx.dckDestColorkey.dwColorSpaceLowValue;
|
||||
|
||||
getRects(&rs,&rd);
|
||||
if(FAILED(lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx))) {
|
||||
initing=false;
|
||||
return 0;
|
||||
}
|
||||
initing=false;
|
||||
|
||||
DDSURFACEDESC dd={sizeof(dd),};
|
||||
if (lpddsOverlay->Lock(NULL,&dd,DDLOCK_WAIT,NULL) != DD_OK) return 0;
|
||||
unsigned char *o=(unsigned char*)dd.lpSurface;
|
||||
if (uyvy_output||yuy2_output)
|
||||
{
|
||||
int x=dd.lPitch*height/2;
|
||||
while (x--)
|
||||
{
|
||||
if (uyvy_output)
|
||||
{
|
||||
*o++=128;
|
||||
*o++=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*o++=0;
|
||||
*o++=-128;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(o,0,dd.lPitch*height); o+=dd.lPitch*height;
|
||||
memset(o,128,dd.lPitch*height/2);
|
||||
}
|
||||
lpddsOverlay->Unlock(&dd);
|
||||
|
||||
InvalidateRect(hwnd,NULL,TRUE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::getRects(RECT *drs, RECT *drd) {
|
||||
HWND hwnd=m_parent->getHwnd();
|
||||
if(GetParent(hwnd)) hwnd=GetParent(hwnd);
|
||||
|
||||
RECT rd,rs;
|
||||
GetClientRect(hwnd,&rd);
|
||||
ClientToScreen(hwnd,(LPPOINT)&rd);
|
||||
ClientToScreen(hwnd,((LPPOINT)&rd) + 1);
|
||||
|
||||
m_parent->adjustAspect(rd);
|
||||
rd.left-=m_mon_x;
|
||||
rd.right-=m_mon_x;
|
||||
rd.top-=m_mon_y;
|
||||
rd.bottom-=m_mon_y;
|
||||
|
||||
memset(&rs,0,sizeof(rs));
|
||||
rs.right=width;
|
||||
rs.bottom=height;
|
||||
|
||||
//resize overlay for off-screen
|
||||
RECT rfull;
|
||||
//m_parent->getViewport(&rfull,NULL,1); //FUCKO: assume monitor 0
|
||||
m_parent->getViewport(&rfull,hwnd,1); //FUCKO: okay to use this hwnd? (fixes multimon! -RG)
|
||||
if(rd.right>rfull.right) {
|
||||
int diff=rd.right-rfull.right;
|
||||
float sc=(float)(width)/(float)(rd.right-rd.left);
|
||||
rd.right=rfull.right;
|
||||
rs.right=width-(int)(diff*sc);
|
||||
}
|
||||
if(rd.left<rfull.left) {
|
||||
int diff=rfull.left-rd.left;
|
||||
float sc=(float)(width)/(float)(rd.right-rd.left);
|
||||
rd.left=rfull.left;
|
||||
rs.left=(int)(diff*sc);
|
||||
}
|
||||
if(rd.bottom>rfull.bottom) {
|
||||
int diff=rd.bottom-rfull.bottom;
|
||||
float sc=(float)(height)/(float)(rd.bottom-rd.top);
|
||||
rd.bottom=rfull.bottom;
|
||||
rs.bottom=height-(int)(diff*sc);
|
||||
}
|
||||
if(rd.top<rfull.top) {
|
||||
int diff=rfull.top-rd.top;
|
||||
float sc=(float)(height)/(float)(rd.bottom-rd.top);
|
||||
rd.top=rfull.top;
|
||||
rs.top=(int)(diff*sc);
|
||||
}
|
||||
|
||||
if (capsDrv.dwCaps & DDCAPS_ALIGNSIZESRC && uDestSizeAlign) {
|
||||
rs.left = (int)((rs.left+uDestSizeAlign-1)/uDestSizeAlign)*uDestSizeAlign;
|
||||
rs.right = (int)((rs.right+uDestSizeAlign-1)/uDestSizeAlign)*uDestSizeAlign;
|
||||
}
|
||||
if (capsDrv.dwCaps & DDCAPS_ALIGNSIZEDEST && uDestSizeAlign) {
|
||||
rd.left = (int)((rd.left+uDestSizeAlign-1)/uDestSizeAlign)*uDestSizeAlign;
|
||||
rd.right = (int)((rd.right+uDestSizeAlign-1)/uDestSizeAlign)*uDestSizeAlign;
|
||||
}
|
||||
|
||||
*drd=rd;
|
||||
*drs=rs;
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::timerCallback() {
|
||||
if(!m_parent) return;
|
||||
|
||||
RECT rd,rs;
|
||||
getRects(&rs,&rd);
|
||||
|
||||
if(memcmp(&m_oldrd,&rd,sizeof(RECT))) {
|
||||
m_oldrd=rd;
|
||||
if(!initing && lpddsOverlay)
|
||||
if(FAILED(lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx))) {
|
||||
needchange=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int OverlayVideoOutput::onPaint(HWND hwnd, HDC hdc) {
|
||||
if(!m_parent) return 0;
|
||||
|
||||
PAINTSTRUCT p;
|
||||
BeginPaint(hwnd,&p);
|
||||
|
||||
RECT r;
|
||||
GetClientRect(hwnd,&r);
|
||||
LOGBRUSH lb={BS_SOLID,RGB(OV_COL_R,OV_COL_G,OV_COL_B),};
|
||||
HBRUSH br=CreateBrushIndirect(&lb);
|
||||
FillRect(p.hdc,&r,br);
|
||||
DeleteObject(br);
|
||||
|
||||
if (curSubtitle)
|
||||
{
|
||||
int m_lastsubxp=curSubtitle->xPos;
|
||||
int m_lastsubyp=curSubtitle->yPos;
|
||||
|
||||
HDC out=p.hdc;
|
||||
|
||||
HGDIOBJ oldobj=SelectObject(out,subFont);
|
||||
|
||||
SetBkMode(out,TRANSPARENT);
|
||||
int centerflags=0;
|
||||
if (m_lastsubxp < 127) centerflags |= DT_LEFT;
|
||||
else if (m_lastsubxp > 127) centerflags |= DT_RIGHT;
|
||||
else centerflags |= DT_CENTER;
|
||||
|
||||
if (m_lastsubyp < 127) centerflags |= DT_TOP;
|
||||
else if (m_lastsubyp > 127) centerflags |= DT_BOTTOM;
|
||||
|
||||
// draw outline
|
||||
SetTextColor(out,RGB(0,0,0));
|
||||
for (int y = -1; y < 2; y++)
|
||||
for (int x = -1; x < 2; x++)
|
||||
{
|
||||
if(!y && !x) continue;
|
||||
RECT r2={subRect.left+x,subRect.top+y,subRect.right+x,subRect.bottom+y};
|
||||
DrawText(out,curSubtitle->text,-1,&r2,centerflags|DT_NOCLIP|DT_NOPREFIX);
|
||||
}
|
||||
// draw text
|
||||
SetTextColor(out,RGB(curSubtitle->colorRed,curSubtitle->colorGreen,curSubtitle->colorBlue));
|
||||
DrawText(out,curSubtitle->text,-1,&subRect,centerflags|DT_NOCLIP|DT_NOPREFIX);
|
||||
SelectObject(out,oldobj);
|
||||
}
|
||||
|
||||
EndPaint(hwnd,&p);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::displayFrame(const char *buf, int size, int time) {
|
||||
if(!m_parent) return;
|
||||
|
||||
DDSURFACEDESC dd={sizeof(dd),};
|
||||
if (m_parent->vid_vsync) lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);
|
||||
HRESULT result;
|
||||
if ((result=lpddsOverlay->Lock(NULL,&dd,DDLOCK_WAIT,NULL)) != DD_OK) {
|
||||
//CT>FUCKO:reenable me (ctrl+alt+del on win2k)
|
||||
//if(result==DDERR_SURFACELOST) width=-1; //will try to recreate the surface in the next processData() call
|
||||
return;
|
||||
}
|
||||
if(type==NSV_MAKETYPE('Y','V','1','2')) {
|
||||
const YV12_PLANES *planes=(YV12_PLANES *)buf;
|
||||
if (uyvy_output||yuy2_output) { // YV12planar->UYVY or YUY2
|
||||
unsigned char *o=(unsigned char*)dd.lpSurface;
|
||||
const unsigned char *yi=planes->y.baseAddr;
|
||||
const unsigned char *ui=planes->u.baseAddr;
|
||||
const unsigned char *vi=planes->v.baseAddr;
|
||||
int y=height;
|
||||
if (flip) o+=dd.lPitch*(height-1);
|
||||
while (y>0) {
|
||||
int x=width;
|
||||
unsigned char *oo=o;
|
||||
|
||||
if (uyvy_output) while (x>0) {
|
||||
o[0]=*ui++; o[1]=*yi++; o[2]=*vi++; o[3]=*yi++;
|
||||
o+=4; x-=2;
|
||||
}
|
||||
else while (x>0) {
|
||||
o[0]=*yi++; o[1]=*ui++; o[2]=*yi++; o[3]=*vi++;
|
||||
o+=4; x-=2;
|
||||
}
|
||||
ui-=width/2;
|
||||
vi-=width/2;
|
||||
yi+=planes->y.rowBytes-width;
|
||||
x=width;
|
||||
if (flip) o=oo-dd.lPitch;
|
||||
else o+=dd.lPitch-width*2;
|
||||
oo=o;
|
||||
if (uyvy_output) while (x>0) {
|
||||
o[0]=*ui++; o[1]=*yi++; o[2]=*vi++; o[3]=*yi++;
|
||||
o+=4; x-=2;
|
||||
} else while (x>0) {
|
||||
o[0]=*yi++; o[1]=*ui++; o[2]=*yi++; o[3]=*vi++;
|
||||
o+=4; x-=2;
|
||||
}
|
||||
if (flip) o=oo-dd.lPitch;
|
||||
else o+=dd.lPitch-width*2;
|
||||
ui+=planes->u.rowBytes-(width/2);
|
||||
vi+=planes->v.rowBytes-(width/2);
|
||||
yi+=planes->y.rowBytes-width;
|
||||
y-=2;
|
||||
}
|
||||
} else { // woo native YV12 copy
|
||||
int f=!!flip;
|
||||
char *o=(char*)dd.lpSurface+(f*height*dd.lPitch);
|
||||
const char *i=(const char*)planes->y.baseAddr;
|
||||
int d_o=dd.lPitch;
|
||||
if (f) d_o=-d_o;
|
||||
else o-=d_o;
|
||||
|
||||
int h2=height;
|
||||
while (h2--) {
|
||||
o+=d_o; memcpy(o,i,width); i+=planes->y.rowBytes;
|
||||
}
|
||||
|
||||
d_o/=2;
|
||||
|
||||
int w2=width/2;
|
||||
h2=height/2;
|
||||
i=(const char*)planes->v.baseAddr;
|
||||
o=(char*)dd.lpSurface+(height*dd.lPitch*(f+4))/4;
|
||||
|
||||
if (!f) o-=d_o;
|
||||
while (h2--) {
|
||||
o+=d_o; memcpy(o,i,w2); i+=planes->v.rowBytes;
|
||||
}
|
||||
o=(char*)dd.lpSurface+(height*dd.lPitch*(f+5))/4;
|
||||
i=(const char*)planes->u.baseAddr;
|
||||
h2=height/2;
|
||||
|
||||
if (!f) o-=d_o;
|
||||
while (h2--) {
|
||||
o+=d_o; memcpy(o,i,w2);i+=planes->u.rowBytes;
|
||||
}
|
||||
}
|
||||
} else if(type==NSV_MAKETYPE('Y','U','Y','2') || type==NSV_MAKETYPE('U','Y','V','Y')) {
|
||||
const char *a=buf;
|
||||
char *b=(char *)dd.lpSurface;
|
||||
int l=width*2,l2=dd.lPitch;
|
||||
if(flip) {
|
||||
b+=(height-1)*l2;
|
||||
l2=-l2;
|
||||
}
|
||||
int is_uyvy=type==NSV_MAKETYPE('U','Y','V','Y');
|
||||
if (uyvy_output && !is_uyvy || (yuy2_output && is_uyvy)) // convert to uyvy
|
||||
{
|
||||
for(int i=0;i<height;i++) {
|
||||
int x=width/2;
|
||||
while (x-->0) {
|
||||
b[0]=a[1];
|
||||
b[1]=a[0];
|
||||
b[2]=a[3];
|
||||
b[3]=a[2];
|
||||
a+=4;
|
||||
b+=4;
|
||||
}
|
||||
memcpy(b,a,l);
|
||||
b+=l2;
|
||||
a+=l;
|
||||
}
|
||||
} else {
|
||||
//wee straight YUY2 copy
|
||||
for(int i=0;i<height;i++) {
|
||||
memcpy(b,a,l);
|
||||
b+=l2;
|
||||
a+=l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lpddsOverlay->Unlock(&dd);
|
||||
|
||||
if (m_parent->osdShowing())
|
||||
{
|
||||
RECT rs, rd;
|
||||
getRects(&rs,&rd);
|
||||
|
||||
HDC hdc;
|
||||
#if 1 // set both these 1s to 0s to put it back on ryan's mode
|
||||
HWND h=m_parent->getHwnd();
|
||||
hdc=GetDC(h);
|
||||
#else
|
||||
if (lpddsPrimary->GetDC(&hdc)==DD_OK)
|
||||
{
|
||||
#endif
|
||||
m_parent->drawOSD(hdc, &rd);
|
||||
#if 1
|
||||
ReleaseDC(h,hdc);
|
||||
#else
|
||||
lpddsPrimary->ReleaseDC(hdc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::goFullScreen() {
|
||||
/* fullscreen_controls = new GuiObjectWnd;
|
||||
fullscreen_controls->setContent("video.fullscreen_controls");
|
||||
fullscreen_controls->init(m_parent);
|
||||
|
||||
RECT r;
|
||||
Std::getViewport(&r,m_parent->gethWnd(),1);
|
||||
|
||||
RECT nr = r;
|
||||
nr.top = (int)(r.bottom - (r.bottom - r.top) * 0.15);
|
||||
nr.bottom = (int)(r.bottom - (r.bottom - r.top) * 0.05);
|
||||
fullscreen_controls->resizeToRect(&nr);
|
||||
*/
|
||||
is_fullscreen=1;
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::removeFullScreen() {
|
||||
/* delete fullscreen_controls;
|
||||
fullscreen_controls = NULL;*/
|
||||
is_fullscreen=0;
|
||||
}
|
||||
|
||||
int OverlayVideoOutput::showOSD() {
|
||||
// if (fullscreen_controls != NULL) fullscreen_controls->setVisible(TRUE);
|
||||
|
||||
// enabling the following code will cause the top & bottom OSD bars
|
||||
// to squish the image (instead of crop it):
|
||||
/*if(lpddsOverlay) {
|
||||
RECT rd,rs;
|
||||
getRects(&rs,&rd);
|
||||
|
||||
HWND hwnd=m_parent->getHwnd();
|
||||
if(GetParent(hwnd)) hwnd=GetParent(hwnd);
|
||||
|
||||
RECT temp;
|
||||
GetClientRect(hwnd,&temp);
|
||||
int bottom_margin = ((temp.bottom-temp.top) - (rd.bottom-rd.top)) / 2;
|
||||
int pixels_to_clip = max(0, m_parent->getOSDbarHeight() - bottom_margin);
|
||||
rd.bottom -= pixels_to_clip;
|
||||
|
||||
lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx);
|
||||
}*/
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::hideOSD() {
|
||||
//if (fullscreen_controls != NULL) fullscreen_controls->setVisible(FALSE);
|
||||
|
||||
// 1) repaint the OSD area with the overlay color here
|
||||
HWND hwnd = m_parent->getHwnd();
|
||||
if(GetParent(hwnd)) hwnd=GetParent(hwnd);
|
||||
|
||||
HDC hdc = GetDC(hwnd);
|
||||
if (hdc) {
|
||||
RECT r;
|
||||
GetClientRect(hwnd,&r);
|
||||
LOGBRUSH lb={BS_SOLID,RGB(OV_COL_R,OV_COL_G,OV_COL_B),};
|
||||
HBRUSH br=CreateBrushIndirect(&lb);
|
||||
FillRect(hdc,&r,br);
|
||||
DeleteObject(br);
|
||||
|
||||
ReleaseDC(hwnd, hdc);
|
||||
}
|
||||
|
||||
// 2) readjust the overlay destination rectangle
|
||||
/*if(lpddsOverlay) {
|
||||
RECT rd,rs;
|
||||
getRects(&rs,&rd);
|
||||
lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx);
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::drawSubtitle(SubsItem *item) {
|
||||
curSubtitle=item;
|
||||
|
||||
HWND hwnd=m_parent->getHwnd();
|
||||
|
||||
RECT oldrect=subRect;
|
||||
GetClientRect(hwnd,&subRect);
|
||||
|
||||
if(item) {
|
||||
|
||||
RECT oldwinRect=winRect;
|
||||
GetClientRect(hwnd,&winRect);
|
||||
if(!subFont || ((winRect.bottom-winRect.top)!=(oldwinRect.bottom-oldwinRect.top)) || m_fontsize!=item->fontSize) {
|
||||
if(subFont) DeleteObject(subFont);
|
||||
m_fontsize=item->fontSize;
|
||||
subFont=CreateFont(14+item->fontSize+18*(winRect.bottom-winRect.top)/768,0,0,0,FW_SEMIBOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_OUTLINE_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH|FF_DONTCARE,"Arial");
|
||||
}
|
||||
|
||||
HDC out=GetDC(hwnd);
|
||||
SelectObject(out,subFont);
|
||||
SIZE s;
|
||||
GetTextExtentPoint32(out,item->text,strlen(item->text),&s);
|
||||
{
|
||||
// calcul for multiline text
|
||||
const char *p=item->text;
|
||||
int n=0;
|
||||
while(*p!=0) if(*p++=='\n') n++;
|
||||
if(n) s.cy*=(n+1);
|
||||
}
|
||||
|
||||
if (item->xPos > 127) // towards the right
|
||||
{
|
||||
subRect.right -= ((subRect.right-subRect.left) * (255-item->xPos)) / 256;
|
||||
}
|
||||
else if (item->xPos < 127)
|
||||
{
|
||||
subRect.left += ((subRect.right-subRect.left) * item->xPos) / 256;
|
||||
}
|
||||
|
||||
subRect.top += ((subRect.bottom-s.cy-subRect.top) * item->yPos)/255;
|
||||
|
||||
subRect.bottom=subRect.top + s.cy;
|
||||
|
||||
ReleaseDC(hwnd,out);
|
||||
}
|
||||
|
||||
//just redraw the correct portion
|
||||
InvalidateRect(hwnd,&oldrect,TRUE);
|
||||
InvalidateRect(hwnd,&subRect,TRUE);
|
||||
}
|
||||
|
||||
void OverlayVideoOutput::resetSubtitle()
|
||||
{
|
||||
curSubtitle=NULL;
|
||||
subRect.top=65536;
|
||||
}
|
58
Src/nsv/nsvplay/vid_overlay.h
Normal file
58
Src/nsv/nsvplay/vid_overlay.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef _VIDEO_OVERLAY_H
|
||||
#define _VIDEO_OVERLAY_H
|
||||
|
||||
#include <ddraw.h>
|
||||
#include <multimon.h>
|
||||
#include "video.h"
|
||||
|
||||
class SubsItem;
|
||||
|
||||
class OverlayVideoOutput : public VideoOutputChild {
|
||||
public:
|
||||
OverlayVideoOutput();
|
||||
virtual ~OverlayVideoOutput();
|
||||
|
||||
int create(VideoOutput *parent, int w, int h, unsigned int type, int flipit, double aspectratio); //return 1 if ok
|
||||
int needChange() { return needchange; }
|
||||
|
||||
int onPaint(HWND hwnd, HDC hdc);
|
||||
void displayFrame(const char *buf, int size, int time);
|
||||
|
||||
void goFullScreen();
|
||||
void removeFullScreen();
|
||||
|
||||
void timerCallback();
|
||||
|
||||
int showOSD();
|
||||
void hideOSD();
|
||||
|
||||
void drawSubtitle(SubsItem *item);
|
||||
virtual void resetSubtitle();
|
||||
|
||||
private:
|
||||
int width, height, flip;
|
||||
int needchange;
|
||||
unsigned int type;
|
||||
VideoOutput *m_parent;
|
||||
LPDIRECTDRAW lpDD;
|
||||
LPDIRECTDRAWSURFACE lpddsOverlay, lpddsPrimary;
|
||||
DDCAPS capsDrv;
|
||||
unsigned int uDestSizeAlign, uSrcSizeAlign;
|
||||
DWORD dwUpdateFlags;
|
||||
DDOVERLAYFX ovfx;
|
||||
RECT rs,rd;
|
||||
RECT m_oldrd;
|
||||
RECT winRect;
|
||||
|
||||
bool initing;
|
||||
int is_fullscreen, yuy2_output, uyvy_output;
|
||||
|
||||
void getRects(RECT *drs, RECT *drd);
|
||||
|
||||
HFONT subFont;
|
||||
RECT subRect;
|
||||
SubsItem *curSubtitle;
|
||||
int m_fontsize;
|
||||
};
|
||||
|
||||
#endif
|
964
Src/nsv/nsvplay/video.cpp
Normal file
964
Src/nsv/nsvplay/video.cpp
Normal file
@ -0,0 +1,964 @@
|
||||
#include <windows.h>
|
||||
#include <ddraw.h>
|
||||
#include "main.h"
|
||||
#include "video.h"
|
||||
#include "subtitles.h"
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#undef GetSystemMetrics
|
||||
|
||||
#define OSD_ENABLED 1
|
||||
|
||||
#define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
|
||||
#define OV_COL_R 16
|
||||
#define OV_COL_G 0
|
||||
#define OV_COL_B 16
|
||||
#define OSD_TEXT_SIZE 28
|
||||
#define OSD_TEXT_R 192
|
||||
#define OSD_TEXT_G 192
|
||||
#define OSD_TEXT_B 192
|
||||
#define OSD_TEXT_R_HILITE 255
|
||||
#define OSD_TEXT_G_HILITE 255
|
||||
#define OSD_TEXT_B_HILITE 255
|
||||
#define OSD_VOL_COL_R 0
|
||||
#define OSD_VOL_COL_G 0
|
||||
#define OSD_VOL_COL_B 192
|
||||
#define OSD_VOL_BKCOL_R 0
|
||||
#define OSD_VOL_BKCOL_G 0
|
||||
#define OSD_VOL_BKCOL_B 64
|
||||
|
||||
#define TIMER_OSD_ID 1234
|
||||
|
||||
#define CTRLTYPE_SYMBOL 0
|
||||
#define CTRLTYPE_TEXT 1
|
||||
#define CTRLTYPE_PROGRESS 2
|
||||
#define CTRLTYPE_SPACER 3
|
||||
|
||||
#define CTRL_PROGRESSTEXT 0
|
||||
#define CTRL_PROGRESS 1
|
||||
#define CTRL_PROGRESSSPACER 2
|
||||
#define CTRL_REW 3
|
||||
#define CTRL_PLAY 4
|
||||
#define CTRL_PAUSE 5
|
||||
#define CTRL_STOP 6
|
||||
#define CTRL_FFWD 7
|
||||
#define CTRL_VOLSPACER 8
|
||||
#define CTRL_VOLTEXT 9
|
||||
#define CTRL_VOL 10
|
||||
|
||||
int g_ctrl_type[NUM_WIDGETS] = {
|
||||
CTRLTYPE_TEXT,
|
||||
CTRLTYPE_PROGRESS,
|
||||
CTRLTYPE_SPACER,
|
||||
CTRLTYPE_SYMBOL,
|
||||
CTRLTYPE_SYMBOL,
|
||||
CTRLTYPE_SYMBOL,
|
||||
CTRLTYPE_SYMBOL,
|
||||
CTRLTYPE_SYMBOL,
|
||||
CTRLTYPE_SPACER,
|
||||
CTRLTYPE_TEXT,
|
||||
CTRLTYPE_PROGRESS
|
||||
};
|
||||
|
||||
const char *g_ctrl_text[NUM_WIDGETS] = {
|
||||
"Progress ",
|
||||
"",
|
||||
"",
|
||||
"7", // rew
|
||||
"4", // play
|
||||
";", // pause
|
||||
"<", // stop
|
||||
"8", // ffwd
|
||||
"",
|
||||
"Volume ",
|
||||
""
|
||||
};
|
||||
|
||||
int g_ctrl_force_width[NUM_WIDGETS] = {
|
||||
0,
|
||||
96, // progress bar width
|
||||
32, // spacer width
|
||||
0, // rew
|
||||
0, // play
|
||||
0, // pause
|
||||
0, // stop
|
||||
0, // ffwd
|
||||
32, // spacer width
|
||||
0,
|
||||
64 // volume bar width
|
||||
};
|
||||
|
||||
extern HINSTANCE g_hInstance;
|
||||
extern int g_bitmap_id;
|
||||
|
||||
static BOOL WINAPI DDEnumCallbackEx(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm) {
|
||||
VideoOutputChild *ovo=(VideoOutputChild *)lpContext;
|
||||
if(ovo->m_found_devguid) return 1;
|
||||
if(hm==ovo->m_monitor_to_find) {
|
||||
ovo->m_devguid=*lpGUID;
|
||||
ovo->m_found_devguid=1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VideoOutputChild::update_monitor_coords(VideoOutput *parent)
|
||||
{
|
||||
//find the correct monitor if multiple monitor support is present
|
||||
HWND hwnd=parent->getHwnd();
|
||||
m_found_devguid=0;
|
||||
m_mon_x=0;
|
||||
m_mon_y=0;
|
||||
|
||||
HINSTANCE h=LoadLibrary("user32.dll");
|
||||
if (h) {
|
||||
HMONITOR (WINAPI *Mfp)(POINT pt, DWORD dwFlags) = (HMONITOR (WINAPI *)(POINT,DWORD)) GetProcAddress(h,"MonitorFromPoint");
|
||||
HMONITOR (WINAPI *Mfr)(LPCRECT lpcr, DWORD dwFlags) = (HMONITOR (WINAPI *)(LPCRECT, DWORD)) GetProcAddress(h, "MonitorFromRect");
|
||||
HMONITOR (WINAPI *Mfw)(HWND wnd, DWORD dwFlags)=(HMONITOR (WINAPI *)(HWND, DWORD)) GetProcAddress(h, "MonitorFromWindow");
|
||||
BOOL (WINAPI *Gmi)(HMONITOR mon, LPMONITORINFO lpmi) = (BOOL (WINAPI *)(HMONITOR,LPMONITORINFO)) GetProcAddress(h,"GetMonitorInfoA");
|
||||
if (Mfp && Mfr && Mfw && Gmi) {
|
||||
RECT r;
|
||||
GetWindowRect(hwnd,&r);
|
||||
HMONITOR hm=Mfr(&r,NULL);
|
||||
if(hm) {
|
||||
HINSTANCE hdd = LoadLibrary("ddraw.dll");
|
||||
if(hdd) {
|
||||
typedef BOOL (FAR PASCAL * LPDDENUMCALLBACKEXA)(GUID FAR *, LPSTR, LPSTR, LPVOID, HMONITOR);
|
||||
typedef HRESULT (WINAPI * LPDIRECTDRAWENUMERATEEX)( LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags);
|
||||
LPDIRECTDRAWENUMERATEEX lpDDEnumEx;
|
||||
lpDDEnumEx = (LPDIRECTDRAWENUMERATEEX) GetProcAddress(hdd,"DirectDrawEnumerateExA");
|
||||
if (lpDDEnumEx) {
|
||||
m_monitor_to_find=hm;
|
||||
lpDDEnumEx(&DDEnumCallbackEx, this, DDENUM_ATTACHEDSECONDARYDEVICES|DDENUM_NONDISPLAYDEVICES);
|
||||
if(m_found_devguid) {
|
||||
MONITORINFOEX mi;
|
||||
memset(&mi,0,sizeof(mi));
|
||||
mi.cbSize=sizeof(mi);
|
||||
if (Gmi(hm,&mi)) {
|
||||
m_mon_x=mi.rcMonitor.left;
|
||||
m_mon_y=mi.rcMonitor.top;
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeLibrary(hdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeLibrary(h);
|
||||
}
|
||||
}
|
||||
|
||||
int VideoOutput::get_latency()
|
||||
{
|
||||
return vid_vsync?15:0;
|
||||
}
|
||||
|
||||
#undef GetSystemMetrics
|
||||
int VideoOutput::class_refcnt=0;
|
||||
|
||||
void VideoOutput::adjustAspect(RECT &rd)
|
||||
{
|
||||
if (vid_aspectadj)
|
||||
{
|
||||
int outh=rd.bottom-rd.top;
|
||||
int outw=rd.right-rd.left;
|
||||
|
||||
int newh=(int)((aspect*height*outw)/(double)width);
|
||||
int neww=(int)((width*outh)/(height*aspect));
|
||||
|
||||
if (outh > newh) // black bars on top and bottom
|
||||
{
|
||||
int d=outh - newh;
|
||||
rd.top+=d/2;
|
||||
rd.bottom-=d-d/2;
|
||||
}
|
||||
else if (outw > neww) // black bars on left and right
|
||||
{
|
||||
int d=outw - neww;
|
||||
rd.left+=d/2;
|
||||
rd.right-=d-d/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK VideoOutput::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (uMsg == WM_CREATE)
|
||||
{
|
||||
SetWindowLong(hwnd,GWL_USERDATA,(long)((CREATESTRUCT *)lParam)->lpCreateParams);
|
||||
ShowWindow(hwnd,SW_SHOW);
|
||||
if (GetParent(hwnd))
|
||||
{
|
||||
RECT r;
|
||||
GetClientRect(GetParent(hwnd),&r);
|
||||
SetWindowPos(hwnd,NULL,0,0,
|
||||
r.right,
|
||||
r.bottom,
|
||||
SWP_NOACTIVATE|SWP_NOZORDER);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
VideoOutput *_This=(VideoOutput*)GetWindowLong(hwnd,GWL_USERDATA);
|
||||
if (_This) return _This->WindowProc(hwnd,uMsg,wParam,lParam);
|
||||
else return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
void VideoOutput::notifyBufferState(int bufferstate) /* 0-255*/
|
||||
{
|
||||
m_bufferstate=bufferstate;
|
||||
#ifdef ACTIVEX_CONTROL
|
||||
PostMessage( video_hwnd, STATUS_MSG, STATUS_PREBUFFER, bufferstate );
|
||||
#endif
|
||||
if (!m_video_output) {
|
||||
if(GetTickCount()-m_lastbufinvalid>500) {
|
||||
InvalidateRect(video_hwnd,NULL,FALSE);
|
||||
m_lastbufinvalid=GetTickCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT VideoOutput::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_TIMER:
|
||||
case WM_WINDOWPOSCHANGING:
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
case WM_SIZE:
|
||||
case WM_MOVE:
|
||||
case WM_MOVING:
|
||||
if (uMsg == WM_TIMER && wParam == TIMER_OSD_ID) {
|
||||
hideOSD();
|
||||
return 0;
|
||||
}
|
||||
EnterCriticalSection(&m_cs);
|
||||
if(m_video_output) m_video_output->timerCallback();
|
||||
LeaveCriticalSection(&m_cs);
|
||||
if (uMsg == WM_TIMER) return 0;
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
if(is_fs)
|
||||
osdHitTest(LOWORD(lParam),HIWORD(lParam),0);
|
||||
#ifdef ACTIVEX_CONTROL
|
||||
SendMessage( video_hwnd, STATUS_MSG, STATUS_MOUSEPRESS, 1 );
|
||||
#endif
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (m_video_output && m_video_output->onPaint(hwnd,(HDC)wParam)) return 0;
|
||||
if (m_logo && !m_video_output)
|
||||
{
|
||||
PAINTSTRUCT p;
|
||||
BeginPaint(hwnd,&p);
|
||||
|
||||
RECT r;
|
||||
GetClientRect(hwnd,&r);
|
||||
|
||||
HDC out=p.hdc;
|
||||
|
||||
HDC dc=CreateCompatibleDC(NULL);
|
||||
SelectObject(dc,m_logo);
|
||||
int xp=(r.right-r.left-m_logo_w)/2;
|
||||
int yp=(r.bottom-r.top-m_logo_h)/2;
|
||||
BitBlt(out,xp,yp,m_logo_w,m_logo_h,dc,0,0,SRCCOPY);
|
||||
|
||||
int bs=m_bufferstate;
|
||||
if (bs < 16) bs=16;
|
||||
|
||||
|
||||
HGDIOBJ oldobj1=SelectObject(out,CreateSolidBrush(RGB(0,0,0)));
|
||||
HGDIOBJ oldobj2=SelectObject(out,CreatePen(PS_SOLID,0,RGB(0,0,0)));
|
||||
Rectangle(out,r.left,r.top,r.right,yp);
|
||||
if (m_statusmsg)
|
||||
Rectangle(out,r.left,yp+m_logo_h,r.right,r.bottom);
|
||||
else
|
||||
{
|
||||
Rectangle(out,r.left,yp+m_logo_h+2+9,r.right,r.bottom);
|
||||
Rectangle(out,xp + ((bs * (m_logo_w+2))>>8),yp+m_logo_h+2,r.right, yp+9+m_logo_h+2);
|
||||
}
|
||||
Rectangle(out,r.left,yp,xp-1,yp+m_logo_h+9+2);
|
||||
Rectangle(out,xp+m_logo_w+1,yp,r.right,yp+m_logo_h+2);
|
||||
DeleteObject(SelectObject(out,oldobj2));
|
||||
DeleteObject(SelectObject(out,oldobj1));
|
||||
|
||||
if (m_statusmsg)
|
||||
{
|
||||
RECT subr={0,yp+m_logo_h+2,r.right,r.bottom};
|
||||
SetTextColor(out,RGB(255,255,255));
|
||||
SetBkMode(out,TRANSPARENT);
|
||||
DrawText(out,m_statusmsg,-1,&subr,DT_TOP|DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
|
||||
}
|
||||
else
|
||||
{
|
||||
yp+=m_logo_h+2;
|
||||
if (bs)
|
||||
{
|
||||
HGDIOBJ oldobj1=SelectObject(out,CreateSolidBrush(RGB(128,128,128)));
|
||||
HGDIOBJ oldobj2=SelectObject(out,CreatePen(PS_SOLID,0,RGB(255,255,255)));
|
||||
Rectangle(out,xp-1,yp,xp + ((bs * (m_logo_w+2))>>8), yp+9);
|
||||
DeleteObject(SelectObject(out,oldobj2));
|
||||
DeleteObject(SelectObject(out,oldobj1));
|
||||
}
|
||||
}
|
||||
DeleteDC(dc);
|
||||
EndPaint(hwnd,&p);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_USER+0x1:
|
||||
m_need_change=1;
|
||||
break;
|
||||
|
||||
#ifdef ACTIVEX_CONTROL
|
||||
case STATUS_MSG:
|
||||
SendStatus( wParam, lParam );
|
||||
break;
|
||||
#endif
|
||||
|
||||
case WM_KEYDOWN:
|
||||
if(wParam==27 && is_fs) remove_fullscreen();
|
||||
break;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
if(is_fs) {
|
||||
if (ignore_mousemove_count>0) {
|
||||
ignore_mousemove_count--;
|
||||
}
|
||||
else if (abs(osdLastMouseX - LOWORD(lParam)) + abs(osdLastMouseY - HIWORD(lParam)) > 1) {
|
||||
KillTimer(hwnd, TIMER_OSD_ID);
|
||||
showOSD();
|
||||
SetTimer(hwnd, TIMER_OSD_ID, 2000, NULL);
|
||||
|
||||
if (wParam & MK_LBUTTON)
|
||||
osdHitTest(LOWORD(lParam),HIWORD(lParam),1);
|
||||
else
|
||||
osdHitTest(LOWORD(lParam),HIWORD(lParam),-1);
|
||||
}
|
||||
osdLastMouseX = LOWORD(lParam);
|
||||
osdLastMouseY = HIWORD(lParam);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (m_msgcallback)
|
||||
{
|
||||
return m_msgcallback(m_msgcallback_tok,hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
|
||||
}
|
||||
|
||||
VideoOutput::VideoOutput(HWND parent_hwnd, int initxpos, int initypos)
|
||||
{
|
||||
curSubtitle=NULL;
|
||||
m_statusmsg=0;
|
||||
m_bufferstate=0;
|
||||
m_msgcallback=0;
|
||||
m_msgcallback_tok=0;
|
||||
video_hwnd=video_parent_hwnd=0;
|
||||
decoder=0;
|
||||
|
||||
vid_aspectadj=true;
|
||||
vid_overlays=true;
|
||||
vid_ddraw=true;
|
||||
vid_vsync=true;
|
||||
aspect=1.0;
|
||||
m_need_change=false;
|
||||
|
||||
width=height=flip=uyvy_output=yuy2_output=is_fs=ignore_mousemove_count=show_osd=0;
|
||||
oldfsparent=0;
|
||||
memset(&oldfsrect,0,sizeof(oldfsrect));
|
||||
memset(&lastfsrect,0,sizeof(lastfsrect));
|
||||
oldfsstyle=0;
|
||||
|
||||
m_video_output=NULL;
|
||||
|
||||
osdFontText=NULL;
|
||||
osdFontSymbol=NULL;
|
||||
osdProgressBrushBg=NULL;
|
||||
osdProgressBrushFg=NULL;
|
||||
osdProgressPenBg=NULL;
|
||||
osdProgressPenFg=NULL;
|
||||
osdProgressPenBgHilite=NULL;
|
||||
osdBlackBrush=NULL;
|
||||
osdMemDC=NULL;
|
||||
osdMemBM=NULL;
|
||||
osdOldBM=NULL;
|
||||
osdMemBMW=0;
|
||||
osdMemBMH=0;
|
||||
osdLastMouseX=-1;
|
||||
osdLastMouseY=-1;
|
||||
|
||||
for (int i=0; i<NUM_WIDGETS; i++)
|
||||
SetRect(&ctrlrect[i], 0, 0, 0, 0);
|
||||
ctrlrects_ready = 0;
|
||||
|
||||
resetSubtitle();
|
||||
|
||||
WNDCLASS wc={0,};
|
||||
|
||||
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.lpszClassName = "NSVplay";
|
||||
LOGBRUSH lb={BS_SOLID,RGB(OV_COL_R,OV_COL_G,OV_COL_B),};
|
||||
wc.hbrBackground=CreateBrushIndirect(&lb);
|
||||
if (!class_refcnt) RegisterClass(&wc);
|
||||
class_refcnt++;
|
||||
|
||||
m_logo=(HBITMAP)LoadImage(g_hInstance,MAKEINTRESOURCE(g_bitmap_id),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
|
||||
BITMAP bm;
|
||||
GetObject(m_logo, sizeof(BITMAP), &bm);
|
||||
m_logo_w=bm.bmWidth;
|
||||
m_logo_h=bm.bmHeight;
|
||||
if(m_logo_h<0) m_logo_h=-m_logo_h;
|
||||
|
||||
InitializeCriticalSection(&m_cs);
|
||||
|
||||
video_hwnd=CreateWindowEx(0,wc.lpszClassName, "NSV Player",parent_hwnd?WS_CHILD:(WS_OVERLAPPEDWINDOW&(~WS_MAXIMIZEBOX)),
|
||||
initxpos,initypos,320,200,
|
||||
parent_hwnd, NULL,wc.hInstance,(void*)this);
|
||||
|
||||
video_parent_hwnd=parent_hwnd;
|
||||
|
||||
m_lastbufinvalid=0;
|
||||
|
||||
#ifdef ACTIVEX_CONTROL
|
||||
m_firstframe = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
VideoOutputChild *VideoOutput::createVideoOutput(int n) {
|
||||
if(!vid_overlays && !vid_ddraw) vid_overlays=true;
|
||||
|
||||
if(!vid_overlays) n++;
|
||||
if(n==0) return new OverlayVideoOutput();
|
||||
if(!vid_ddraw) n++;
|
||||
if(n==1) return new DDrawVideoOutput();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VideoOutput::open(int w, int h, int vflip, double aspectratio, unsigned int fmt)
|
||||
{
|
||||
EnterCriticalSection(&m_cs);
|
||||
delete(m_video_output);
|
||||
m_video_output=NULL;
|
||||
|
||||
if (!w) w=320;
|
||||
if (!h) h=240;
|
||||
width=w;
|
||||
height=h;
|
||||
flip=vflip;
|
||||
type=fmt;
|
||||
is_fs=0;
|
||||
ignore_mousemove_count=0;
|
||||
show_osd=0;
|
||||
aspect=aspectratio;
|
||||
|
||||
for(int i=0;m_video_output=createVideoOutput(i);i++) {
|
||||
if(m_video_output->create(this,w,h,fmt,vflip,aspectratio)) {
|
||||
LeaveCriticalSection(&m_cs);
|
||||
if (!GetParent(video_hwnd)) {
|
||||
RECT r,r2;
|
||||
int ow=width,oh=height;
|
||||
if (aspect > 0.001)
|
||||
{
|
||||
if (aspect < 1.0) ow=(int)(ow/aspect);
|
||||
else oh=(int)(oh*aspect);
|
||||
}
|
||||
GetWindowRect(video_hwnd,&r);
|
||||
GetClientRect(video_hwnd,&r2);
|
||||
SetWindowPos(video_hwnd,NULL,0,0,
|
||||
ow+(r.right-r.left)-(r2.right-r2.left),
|
||||
oh+(r.bottom-r.top)-(r2.bottom-r2.top),
|
||||
SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
delete(m_video_output);
|
||||
}
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VideoOutput::draw(void *frame)
|
||||
{
|
||||
if (!m_video_output || !frame) return;
|
||||
if ((m_video_output && m_video_output->needChange()) || m_need_change) {
|
||||
open(width,height,flip,aspect,type);
|
||||
m_need_change=0;
|
||||
}
|
||||
#ifdef ACTIVEX_CONTROL
|
||||
if ( m_firstframe ) {
|
||||
m_firstframe = 0;
|
||||
PostMessage( video_hwnd, STATUS_MSG, STATUS_FIRSTFRAME, 1 );
|
||||
}
|
||||
#endif
|
||||
if (m_video_output) m_video_output->displayFrame((const char *)frame,0,0);
|
||||
}
|
||||
|
||||
VideoOutput::~VideoOutput()
|
||||
{
|
||||
free(m_statusmsg);
|
||||
delete(m_video_output);
|
||||
DestroyWindow(video_hwnd);
|
||||
if (!--class_refcnt) UnregisterClass("NSVplay",GetModuleHandle(NULL));
|
||||
if(osdFontText) DeleteObject(osdFontText);
|
||||
if(osdFontSymbol) DeleteObject(osdFontSymbol);
|
||||
if(osdProgressBrushBg) DeleteObject(osdProgressBrushBg);
|
||||
if(osdProgressBrushFg) DeleteObject(osdProgressBrushFg);
|
||||
if(osdBlackBrush ) DeleteObject(osdBlackBrush );
|
||||
if(osdProgressPenBg ) DeleteObject(osdProgressPenBg );
|
||||
if(osdProgressPenFg ) DeleteObject(osdProgressPenFg );
|
||||
if(osdProgressPenBgHilite) DeleteObject(osdProgressPenBgHilite);
|
||||
if(osdMemDC) {
|
||||
SelectObject(osdMemDC,osdOldBM); // delete our doublebuffer
|
||||
DeleteDC(osdMemDC);
|
||||
}
|
||||
if(osdMemBM) DeleteObject(osdMemBM);
|
||||
|
||||
|
||||
DeleteCriticalSection(&m_cs);
|
||||
}
|
||||
|
||||
void VideoOutput::close()
|
||||
{
|
||||
delete(m_video_output);
|
||||
m_video_output=NULL;
|
||||
}
|
||||
|
||||
void VideoOutput::getViewport(RECT *r, HWND wnd, int full) {
|
||||
POINT *p=NULL;
|
||||
RECT *sr=NULL;
|
||||
if (p || sr || wnd) {
|
||||
HINSTANCE h=LoadLibrary("user32.dll");
|
||||
if (h) {
|
||||
HMONITOR (WINAPI *Mfp)(POINT pt, DWORD dwFlags) = (HMONITOR (WINAPI *)(POINT,DWORD)) GetProcAddress(h,"MonitorFromPoint");
|
||||
HMONITOR (WINAPI *Mfr)(LPCRECT lpcr, DWORD dwFlags) = (HMONITOR (WINAPI *)(LPCRECT, DWORD)) GetProcAddress(h, "MonitorFromRect");
|
||||
HMONITOR (WINAPI *Mfw)(HWND wnd, DWORD dwFlags)=(HMONITOR (WINAPI *)(HWND, DWORD)) GetProcAddress(h, "MonitorFromWindow");
|
||||
BOOL (WINAPI *Gmi)(HMONITOR mon, LPMONITORINFO lpmi) = (BOOL (WINAPI *)(HMONITOR,LPMONITORINFO)) GetProcAddress(h,"GetMonitorInfoA");
|
||||
if (Mfp && Mfr && Mfw && Gmi) {
|
||||
HMONITOR hm = NULL;
|
||||
if (p)
|
||||
hm=Mfp(*p,MONITOR_DEFAULTTONULL);
|
||||
else if (sr)
|
||||
hm=Mfr(sr,MONITOR_DEFAULTTONULL);
|
||||
else if (wnd)
|
||||
hm=Mfw(wnd,MONITOR_DEFAULTTONULL);
|
||||
if (hm) {
|
||||
MONITORINFOEX mi;
|
||||
memset(&mi,0,sizeof(mi));
|
||||
mi.cbSize=sizeof(mi);
|
||||
|
||||
if (Gmi(hm,&mi)) {
|
||||
if(!full) *r=mi.rcWork;
|
||||
else *r=mi.rcMonitor;
|
||||
FreeLibrary(h);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeLibrary(h);
|
||||
}
|
||||
}
|
||||
if (full)
|
||||
{ // this might be borked =)
|
||||
r->top=r->left=0;
|
||||
r->right=::GetSystemMetrics(SM_CXSCREEN);
|
||||
r->bottom=::GetSystemMetrics(SM_CYSCREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemParametersInfo(SPI_GETWORKAREA,0,r,0);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoOutput::fullscreen()
|
||||
{
|
||||
if (is_fs) return;
|
||||
if(!m_video_output) return;
|
||||
is_fs=1;
|
||||
ignore_mousemove_count=2;
|
||||
|
||||
oldfsparent=GetParent(video_hwnd);
|
||||
oldfsstyle=GetWindowLong(video_hwnd,GWL_STYLE);
|
||||
if (!oldfsparent) GetWindowRect(video_hwnd,&oldfsrect);
|
||||
else GetClientRect(video_hwnd,&oldfsrect);
|
||||
getViewport(&lastfsrect,video_hwnd,1);
|
||||
|
||||
SetParent(video_hwnd,NULL);
|
||||
SetWindowLong(video_hwnd,GWL_STYLE,WS_POPUP|WS_VISIBLE);
|
||||
SetWindowPos(video_hwnd, HWND_TOPMOST, lastfsrect.left, lastfsrect.top, lastfsrect.right-lastfsrect.left, lastfsrect.bottom-lastfsrect.top, SWP_DRAWFRAME);
|
||||
SetFocus(video_hwnd);
|
||||
|
||||
resetSubtitle();
|
||||
|
||||
//showOSD();
|
||||
|
||||
//SetCursor(NULL);
|
||||
}
|
||||
|
||||
void VideoOutput::getOutputSize(int *w, int *h)
|
||||
{
|
||||
RECT r2;
|
||||
GetClientRect(video_hwnd,&r2);
|
||||
*w=r2.right-r2.left;
|
||||
*h=r2.bottom-r2.top;
|
||||
}
|
||||
|
||||
void VideoOutput::setOutputSize(int w, int h)
|
||||
{
|
||||
RECT r,r2;
|
||||
GetWindowRect(video_hwnd,&r);
|
||||
GetClientRect(video_hwnd,&r2);
|
||||
SetWindowPos(video_hwnd, 0, 0,0,
|
||||
w+(r.right-r.left)-(r2.right-r2.left),
|
||||
h+(r.bottom-r.top)-(r2.bottom-r2.top),
|
||||
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
void VideoOutput::remove_fullscreen()
|
||||
{
|
||||
if(!is_fs) return;
|
||||
|
||||
SetParent(video_hwnd,oldfsparent);
|
||||
SetWindowLong(video_hwnd,GWL_STYLE,oldfsstyle);
|
||||
// note: when returning from fullscreen *on a secondary monitor*,
|
||||
// be careful how you set the new window Z order.
|
||||
// nsvplay.exe: only HWND_NOTOPMOST works
|
||||
// nsvplayX.exe: only HWND_TOP works
|
||||
SetWindowPos(video_hwnd, oldfsparent ? HWND_TOP : HWND_NOTOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right-oldfsrect.left, oldfsrect.bottom-oldfsrect.top, SWP_FRAMECHANGED);
|
||||
SetFocus(oldfsparent ? oldfsparent : video_hwnd);
|
||||
|
||||
is_fs=0;
|
||||
show_osd=0;
|
||||
ctrlrects_ready=0;
|
||||
resetSubtitle();
|
||||
|
||||
hideOSD();
|
||||
}
|
||||
|
||||
int VideoOutput::is_fullscreen()
|
||||
{
|
||||
return is_fs;
|
||||
}
|
||||
|
||||
void VideoOutput::showStatusMsg(const char *text)
|
||||
{
|
||||
m_statusmsg=_strdup(text);
|
||||
InvalidateRect(video_hwnd,NULL,TRUE);
|
||||
}
|
||||
|
||||
void VideoOutput::drawSubtitle(SubsItem *item)
|
||||
{
|
||||
if(!item) {
|
||||
if(curSubtitle) {
|
||||
m_video_output->drawSubtitle(NULL);
|
||||
curSubtitle=NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(curSubtitle==item) return;
|
||||
|
||||
curSubtitle=item;
|
||||
|
||||
m_video_output->drawSubtitle(curSubtitle);
|
||||
}
|
||||
|
||||
void VideoOutput::resetSubtitle()
|
||||
{
|
||||
curSubtitle=NULL;
|
||||
if(m_video_output) m_video_output->resetSubtitle();
|
||||
}
|
||||
|
||||
void VideoOutput::showOSD() {
|
||||
if(OSD_ENABLED && m_video_output) {
|
||||
KillTimer(video_hwnd, TIMER_OSD_ID);
|
||||
if (!show_osd)
|
||||
m_video_output->showOSD();
|
||||
SetTimer(video_hwnd, TIMER_OSD_ID, 2000, NULL);
|
||||
show_osd = 1;
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
}
|
||||
}
|
||||
|
||||
void VideoOutput::hideOSD() {
|
||||
if(OSD_ENABLED && m_video_output) {
|
||||
KillTimer(video_hwnd, TIMER_OSD_ID);
|
||||
m_video_output->hideOSD();
|
||||
show_osd = 0;
|
||||
SetCursor(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoOutput::drawOSD(HDC hdc, RECT *rg) {
|
||||
if(m_video_output && show_osd) {
|
||||
|
||||
if (!osdMemDC ) osdMemDC = CreateCompatibleDC(hdc);
|
||||
if (!osdFontText) osdFontText=CreateFont(OSD_TEXT_SIZE,0,0,0,FW_SEMIBOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_OUTLINE_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH|FF_DONTCARE,"Arial");
|
||||
if (!osdFontSymbol) osdFontSymbol=CreateFont(OSD_TEXT_SIZE,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,SYMBOL_CHARSET,OUT_OUTLINE_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH,"Webdings");
|
||||
if (!osdProgressBrushBg) osdProgressBrushBg = CreateSolidBrush(RGB(OSD_VOL_BKCOL_R,OSD_VOL_BKCOL_G,OSD_VOL_BKCOL_B));
|
||||
if (!osdProgressBrushFg) osdProgressBrushFg = CreateSolidBrush(RGB(OSD_VOL_COL_R,OSD_VOL_COL_G,OSD_VOL_COL_B));
|
||||
if (!osdBlackBrush ) osdBlackBrush = CreateSolidBrush(RGB(0,0,0));//OV_COL_R,OV_COL_G,OV_COL_B));
|
||||
if (!osdProgressPenBg ) osdProgressPenBg = CreatePen(PS_SOLID,0,RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
|
||||
if (!osdProgressPenFg ) osdProgressPenFg = CreatePen(PS_NULL,0,RGB(0,0,0));
|
||||
if (!osdProgressPenBgHilite) osdProgressPenBgHilite = CreatePen(PS_SOLID,0,RGB(OSD_TEXT_R_HILITE,OSD_TEXT_G_HILITE,OSD_TEXT_B_HILITE));
|
||||
|
||||
COLORREF fg = GetTextColor(osdMemDC);
|
||||
COLORREF bg = GetBkColor(osdMemDC);
|
||||
SetTextColor(osdMemDC, RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
|
||||
SetBkColor(osdMemDC, RGB(0,0,0));//OV_COL_R,OV_COL_G,OV_COL_B));
|
||||
|
||||
HGDIOBJ oldfont = SelectObject(osdMemDC, osdFontText);
|
||||
HGDIOBJ oldbrush = SelectObject(osdMemDC, osdProgressBrushBg);
|
||||
HGDIOBJ oldpen = SelectObject(osdMemDC, osdProgressPenBg);
|
||||
|
||||
RECT fullr;
|
||||
GetClientRect(video_hwnd,&fullr);
|
||||
ClientToScreen(video_hwnd,(LPPOINT)&fullr);
|
||||
ClientToScreen(video_hwnd,((LPPOINT)&fullr) + 1);
|
||||
// transform coords from windows desktop coords (where 0,0==upper-left corner of the primary monitor)
|
||||
// to the coords for the monitor we're displaying on:
|
||||
fullr.top -= m_video_output->m_mon_y;
|
||||
fullr.left -= m_video_output->m_mon_x;
|
||||
fullr.right -= m_video_output->m_mon_x;
|
||||
fullr.bottom -= m_video_output->m_mon_y;
|
||||
|
||||
if (!ctrlrects_ready) {
|
||||
ctrlrects_ready = 1;
|
||||
|
||||
int net_width = 0;
|
||||
int max_height = 0;
|
||||
int streaming = (decoder && decoder->getlen()==-1) ? 1 : 0;
|
||||
|
||||
for (int i=0; i<NUM_WIDGETS; i++) {
|
||||
if (streaming && (i==CTRL_PROGRESS || i==CTRL_PROGRESSTEXT || i==CTRL_PROGRESSSPACER || i==CTRL_FFWD || i==CTRL_REW)) {
|
||||
// disable progress bar + seek arrows when the NSV is a stream
|
||||
ctrlrect[i].right = -1;
|
||||
continue;
|
||||
}
|
||||
else if (g_ctrl_force_width[i] != 0) {
|
||||
SetRect(&ctrlrect[i], 0, 0, g_ctrl_force_width[i], 0);
|
||||
}
|
||||
else {
|
||||
SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
|
||||
SetRect(&ctrlrect[i], 0, 0, 256, 256);
|
||||
ctrlrect[i].bottom = DrawText(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE|DT_CALCRECT);
|
||||
}
|
||||
net_width += ctrlrect[i].right - ctrlrect[i].left;
|
||||
max_height = max(max_height, ctrlrect[i].bottom - ctrlrect[i].top);
|
||||
}
|
||||
|
||||
// now we know the size of all the controls; now place them.
|
||||
int x = (fullr.right + fullr.left)/2 - net_width/2;
|
||||
SetRect(&ctrlrect_all, 0, 0, 0, 0);
|
||||
for (i=0; i<NUM_WIDGETS; i++)
|
||||
{
|
||||
if (ctrlrect[i].right >= 0) // if control is not disabled...
|
||||
{
|
||||
int this_width = ctrlrect[i].right - ctrlrect[i].left;
|
||||
int this_height = ctrlrect[i].bottom - ctrlrect[i].top ;
|
||||
if (this_height==0) this_height = max_height*2/3;// progress bars
|
||||
ctrlrect[i].top = max_height/2 - this_height/2;
|
||||
ctrlrect[i].bottom = max_height/2 + this_height/2;
|
||||
ctrlrect[i].left = x;
|
||||
ctrlrect[i].right = x + this_width;
|
||||
if (ctrlrect_all.bottom==0) {
|
||||
ctrlrect_all.top = ctrlrect[i].top ;
|
||||
ctrlrect_all.bottom = ctrlrect[i].bottom;
|
||||
}
|
||||
else {
|
||||
ctrlrect_all.top = min(ctrlrect_all.top , ctrlrect[i].top );
|
||||
ctrlrect_all.bottom = max(ctrlrect_all.bottom, ctrlrect[i].bottom);
|
||||
}
|
||||
x += this_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int w = fullr.right - fullr.left;
|
||||
int h = ctrlrect_all.bottom - ctrlrect_all.top;
|
||||
if (!osdMemBM || osdMemBMW != w || osdMemBMH != h) {
|
||||
if (osdMemBM) {
|
||||
SelectObject(osdMemDC,osdOldBM);
|
||||
DeleteObject(osdMemBM);
|
||||
}
|
||||
osdMemBM = CreateCompatibleBitmap(hdc,w,h);
|
||||
osdOldBM = (HBITMAP)SelectObject(osdMemDC, osdMemBM);
|
||||
osdMemBMW = w;
|
||||
osdMemBMH = h;
|
||||
}
|
||||
|
||||
RECT temp;
|
||||
SetRect(&temp, 0, 0, w, h);
|
||||
FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
|
||||
|
||||
for (int i=0; i<NUM_WIDGETS; i++) {
|
||||
if (g_ctrl_type[i] == CTRLTYPE_PROGRESS)
|
||||
{
|
||||
int progress = 0;
|
||||
int max_progress = ctrlrect[i].right - ctrlrect[i].left;
|
||||
switch(i)
|
||||
{
|
||||
case CTRL_VOL:
|
||||
if (decoder)
|
||||
progress = decoder->getvolume()*max_progress/255;
|
||||
break;
|
||||
case CTRL_PROGRESS:
|
||||
if (decoder)
|
||||
{
|
||||
int len = decoder->getlen();
|
||||
if (len>0)
|
||||
progress = decoder->getpos()*max_progress/len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SelectObject(osdMemDC, osdProgressBrushBg);
|
||||
SelectObject(osdMemDC, (i==osdLastClickItem) ? osdProgressPenBgHilite : osdProgressPenBg);
|
||||
RoundRect(osdMemDC, ctrlrect[i].left, ctrlrect[i].top, ctrlrect[i].right, ctrlrect[i].bottom, 3, 3);
|
||||
SelectObject(osdMemDC, osdProgressBrushFg);
|
||||
SelectObject(osdMemDC, osdProgressPenFg);
|
||||
Rectangle(osdMemDC, ctrlrect[i].left+1, ctrlrect[i].top+1, ctrlrect[i].left + progress, ctrlrect[i].bottom);
|
||||
}
|
||||
else if (g_ctrl_type[i] == CTRLTYPE_SYMBOL ||
|
||||
g_ctrl_type[i] == CTRLTYPE_TEXT)
|
||||
{
|
||||
SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
|
||||
SetTextColor(osdMemDC, (i==osdLastClickItem) ? RGB(OSD_TEXT_R_HILITE,OSD_TEXT_G_HILITE,OSD_TEXT_B_HILITE) : RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
|
||||
DrawText(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE);
|
||||
}
|
||||
}
|
||||
|
||||
int x0 = fullr.left;
|
||||
int y0 = fullr.bottom - (ctrlrect_all.bottom - ctrlrect_all.top);
|
||||
BitBlt(hdc,x0,y0,w,h,osdMemDC,0,0,SRCCOPY);
|
||||
|
||||
// display stream title @ the top:
|
||||
#if (SHOW_STREAM_TITLE_AT_TOP)
|
||||
if (decoder)
|
||||
{
|
||||
RECT temp;
|
||||
SetRect(&temp, 0, 0, w, h);
|
||||
FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
|
||||
|
||||
SelectObject(osdMemDC, osdFontText);
|
||||
SetTextColor(osdMemDC, RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
|
||||
char *t=decoder->getTitle();
|
||||
char *buf=(char*)malloc(32+(t?strlen(t):0));
|
||||
|
||||
wsprintf(buf, "%s (%d kbps)", t?t:"", decoder->getBitrate()/1000);
|
||||
char *p=buf;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '_') *p=' ';
|
||||
p++;
|
||||
}
|
||||
DrawText(osdMemDC, buf, -1, &temp, DT_SINGLELINE|DT_CENTER);
|
||||
free(buf);
|
||||
|
||||
SelectObject(osdMemDC, osdFontSymbol);
|
||||
DrawText(osdMemDC, "2r", -1, &temp, DT_SINGLELINE|DT_RIGHT);
|
||||
|
||||
int x0 = fullr.left;
|
||||
int y0 = fullr.top;
|
||||
BitBlt(hdc,x0,y0,w,h,osdMemDC,0,0,SRCCOPY);
|
||||
}
|
||||
|
||||
SelectObject(osdMemDC, oldpen);
|
||||
SelectObject(osdMemDC, oldbrush);
|
||||
SelectObject(osdMemDC, oldfont);
|
||||
SetTextColor(osdMemDC, fg);
|
||||
SetBkColor(osdMemDC, bg);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void VideoOutput::osdHitTest(int x, int y, int dragging)
|
||||
{
|
||||
// dragging == -1: just a mousemove (no clicking)
|
||||
// dragging == 0: user clicked
|
||||
// dragging == 1: user clicked before, and is now dragging/moving mouse
|
||||
|
||||
if (dragging<1)
|
||||
osdLastClickItem = -1;
|
||||
|
||||
// transform (x,y) from screen coords into coords relative to the memDC
|
||||
y = y - ((lastfsrect.bottom - lastfsrect.top) - (ctrlrect_all.bottom - ctrlrect_all.top));
|
||||
|
||||
int i0 = 0;
|
||||
int i1 = NUM_WIDGETS;
|
||||
if (dragging==1) {
|
||||
i0 = osdLastClickItem;
|
||||
i1 = osdLastClickItem+1;
|
||||
}
|
||||
|
||||
for (int i=i0; i<i1; i++)
|
||||
{
|
||||
if (dragging==1 || (x >= ctrlrect[i].left && x <= ctrlrect[i].right && y >= ctrlrect[i].top && y <= ctrlrect[i].bottom))
|
||||
{
|
||||
float t = (x - ctrlrect[i].left) / (float)(ctrlrect[i].right - ctrlrect[i].left);
|
||||
if (t<0) t=0;
|
||||
if (t>1) t=1;
|
||||
if (dragging<1)
|
||||
osdLastClickItem = i;
|
||||
|
||||
switch(i)
|
||||
{
|
||||
case CTRL_VOL:
|
||||
if (decoder && dragging>=0) decoder->setvolume((int)(t*255));
|
||||
return;
|
||||
case CTRL_PROGRESS:
|
||||
if (decoder && dragging>=0)
|
||||
{
|
||||
int len = decoder->getlen();
|
||||
if (len > 0)
|
||||
decoder->seek((int)(t*len));
|
||||
}
|
||||
return;
|
||||
case CTRL_PAUSE:
|
||||
if (decoder && dragging>=0) decoder->pause(1);
|
||||
return;
|
||||
case CTRL_PLAY:
|
||||
if (decoder && dragging>=0) decoder->pause(0);
|
||||
return;
|
||||
case CTRL_STOP:
|
||||
if (decoder && dragging>=0) {
|
||||
decoder->pause(1);
|
||||
remove_fullscreen();
|
||||
}
|
||||
return;
|
||||
case CTRL_REW:
|
||||
case CTRL_FFWD:
|
||||
if (decoder && dragging>=0)
|
||||
{
|
||||
int pos = decoder->getpos();
|
||||
int len = decoder->getlen();
|
||||
if (len > 0)
|
||||
{
|
||||
if (i==CTRL_REW)
|
||||
pos = max(0, pos-15000); // milliseconds to rewind
|
||||
else
|
||||
pos = min(len, pos+30000); // milliseconds to skip ahead
|
||||
decoder->seek(pos);
|
||||
}
|
||||
}
|
||||
return;
|
||||
default:
|
||||
if (dragging<1)
|
||||
osdLastClickItem = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dragging==0)
|
||||
remove_fullscreen();
|
||||
}
|
160
Src/nsv/nsvplay/video.h
Normal file
160
Src/nsv/nsvplay/video.h
Normal file
@ -0,0 +1,160 @@
|
||||
#ifndef _VIDEO_H
|
||||
#define _VIDEO_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <ddraw.h>
|
||||
#include <multimon.h>
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#define NUM_WIDGETS 11
|
||||
|
||||
class VideoOutput;
|
||||
class SubsItem;
|
||||
|
||||
class VideoOutputChild {
|
||||
public:
|
||||
VideoOutputChild() { m_mon_x=m_mon_y=0; }
|
||||
virtual ~VideoOutputChild() { }
|
||||
|
||||
virtual int create(VideoOutput *parent, int w, int h, unsigned int type, int flipit, double aspectratio)=0; //return 1 if ok
|
||||
virtual int needChange()=0; //return 1 if need to renegociate video output
|
||||
|
||||
virtual int onPaint(HWND hwnd, HDC hdc) { return 0; } //return 1 if override
|
||||
virtual void displayFrame(const char *buf, int size, int time)=0;
|
||||
|
||||
virtual void goFullScreen()=0;
|
||||
virtual void removeFullScreen()=0;
|
||||
virtual int showOSD() { return 0; }
|
||||
virtual void hideOSD() { }
|
||||
|
||||
virtual void timerCallback() { }
|
||||
|
||||
virtual void setPalette(RGBQUAD *pal) { }
|
||||
|
||||
virtual void drawSubtitle(SubsItem *item) { }
|
||||
virtual void resetSubtitle() { }
|
||||
|
||||
char m_szTest[512];
|
||||
|
||||
void update_monitor_coords(VideoOutput *parent);
|
||||
int m_mon_x;
|
||||
int m_mon_y;
|
||||
int m_found_devguid;
|
||||
GUID m_devguid;
|
||||
HMONITOR m_monitor_to_find;
|
||||
};
|
||||
|
||||
#include "vid_overlay.h"
|
||||
#include "vid_ddraw.h"
|
||||
|
||||
class VideoOutput : public IVideoOutput {
|
||||
public:
|
||||
VideoOutput(HWND parent_hwnd=NULL, int initxpos=CW_USEDEFAULT, int initypos=CW_USEDEFAULT);
|
||||
~VideoOutput();
|
||||
int open(int w, int h, int vflip, double aspectratio, unsigned int fmt);
|
||||
void close();
|
||||
void draw(void *frame);
|
||||
void drawSubtitle(SubsItem *item);
|
||||
void showStatusMsg(const char *text);
|
||||
void notifyBufferState(int bufferstate); /* 0-255*/
|
||||
int get_latency();
|
||||
void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { m_msgcallback_tok=token; m_msgcallback=msgcallback; }
|
||||
void setNSVDecoder(NSVDecoder *nsv_decoder) { decoder = nsv_decoder; }
|
||||
|
||||
void fullscreen();
|
||||
void remove_fullscreen();
|
||||
int is_fullscreen();
|
||||
|
||||
HWND getHwnd() { return video_hwnd; }
|
||||
|
||||
void adjustAspect(RECT &rd);
|
||||
|
||||
int vid_vsync;
|
||||
int vid_aspectadj;
|
||||
int vid_overlays;
|
||||
int vid_ddraw;
|
||||
|
||||
void getViewport(RECT *r, HWND wnd, int full);
|
||||
void setOutputSize(int w, int h);
|
||||
void getOutputSize(int *w, int *h);
|
||||
|
||||
int osdShowing() { return show_osd; }
|
||||
int osdReady() { return ctrlrects_ready; }
|
||||
void showOSD();
|
||||
void hideOSD();
|
||||
void drawOSD(HDC hdc, RECT *r);
|
||||
int getOSDbarHeight() { return (show_osd && ctrlrects_ready) ? (ctrlrect_all.bottom - ctrlrect_all.top) : 0; };
|
||||
|
||||
private:
|
||||
|
||||
|
||||
LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
static int class_refcnt;
|
||||
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
HWND video_hwnd, video_parent_hwnd;
|
||||
NSVDecoder *decoder;
|
||||
|
||||
double aspect;
|
||||
int width, height, flip;
|
||||
unsigned int type;
|
||||
int uyvy_output,yuy2_output;
|
||||
int i420_output;
|
||||
int is_fs;
|
||||
int ignore_mousemove_count;
|
||||
int show_osd;
|
||||
HWND oldfsparent;
|
||||
RECT oldfsrect; // the old window rect, BEFORE fullscreen mode was entered
|
||||
RECT lastfsrect; // the most recent bounding rect when in fullscreen mode
|
||||
LONG oldfsstyle;
|
||||
|
||||
int m_bufferstate;
|
||||
void resetSubtitle();
|
||||
SubsItem *curSubtitle;
|
||||
|
||||
// ONSCREEN DISPLAY (osd):
|
||||
HFONT osdFontText;
|
||||
HFONT osdFontSymbol;
|
||||
HGDIOBJ osdProgressBrushBg;
|
||||
HGDIOBJ osdProgressBrushFg;
|
||||
HGDIOBJ osdProgressPenBg;
|
||||
HGDIOBJ osdProgressPenFg;
|
||||
HGDIOBJ osdProgressPenBgHilite;
|
||||
HGDIOBJ osdBlackBrush;
|
||||
void osdHitTest(int x, int y, int dragging);
|
||||
int osdLastClickItem;
|
||||
HDC osdMemDC; // memory device context
|
||||
HBITMAP osdMemBM; // memory bitmap (for memDC)
|
||||
HBITMAP osdOldBM; // old bitmap (from memDC)
|
||||
int osdMemBMW; // width of memory bitmap
|
||||
int osdMemBMH; // height of memory bitmap
|
||||
int osdLastMouseX; // for WM_MOUSEMOVE thresholding, so osd isn't spastic
|
||||
int osdLastMouseY; // for WM_MOUSEMOVE thresholding, so osd isn't spastic
|
||||
RECT ctrlrect[NUM_WIDGETS]; // relative to [i.e. (0,0) is] upper left corner of the black strip @ the bottom
|
||||
RECT ctrlrect_all; // relative to [i.e. (0,0) is] upper left corner of the black strip @ the bottom
|
||||
int ctrlrects_ready;
|
||||
|
||||
LRESULT (*m_msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
void *m_msgcallback_tok;
|
||||
|
||||
VideoOutputChild *m_video_output;
|
||||
VideoOutputChild *createVideoOutput(int n);
|
||||
|
||||
CRITICAL_SECTION m_cs;
|
||||
char *m_statusmsg;
|
||||
|
||||
int m_need_change;
|
||||
|
||||
HBITMAP m_logo;
|
||||
int m_logo_w, m_logo_h;
|
||||
|
||||
DWORD m_lastbufinvalid;
|
||||
|
||||
#ifdef ACTIVEX_CONTROL
|
||||
int m_firstframe;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
120
Src/nsv/nsvplay/vp3stub.cpp
Normal file
120
Src/nsv/nsvplay/vp3stub.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "main.h"
|
||||
#include "../../vp32/include/duck_dxl.h"
|
||||
#include "vfw.h"
|
||||
|
||||
extern "C" {
|
||||
void GetImageBufs(DXL_XIMAGE_HANDLE x, YV12_PLANES *p);
|
||||
};
|
||||
|
||||
int vp3_postprocess=0;
|
||||
int vp3_targetcpu=0;
|
||||
|
||||
class VP3_Decoder : public IVideoDecoder {
|
||||
public:
|
||||
VP3_Decoder(int w, int h, int uvflip);
|
||||
~VP3_Decoder();
|
||||
int decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf);
|
||||
void flush() { }
|
||||
|
||||
private:
|
||||
int m_uvflip;
|
||||
int l_tcpu, l_pp;
|
||||
static int init;
|
||||
DXL_XIMAGE_HANDLE xim;
|
||||
YV12_PLANES vidbufdec;
|
||||
};
|
||||
|
||||
int VP3_Decoder::init;
|
||||
|
||||
VP3_Decoder::VP3_Decoder(int w, int h, int uvflip)
|
||||
{
|
||||
l_tcpu=-1;
|
||||
l_pp=-1;
|
||||
if (!init)
|
||||
{
|
||||
init=1;
|
||||
DXL_InitVideoEx(1,1);
|
||||
}
|
||||
m_uvflip=uvflip;
|
||||
vidbufdec.y.baseAddr=0;
|
||||
xim = DXL_AlterXImage( NULL, (unsigned char *)"" ,MAKEFOURCC('V','P','3','1'), DXRGBNULL,w,h);
|
||||
}
|
||||
|
||||
VP3_Decoder::~VP3_Decoder()
|
||||
{
|
||||
if ( xim ) DXL_DestroyXImage( xim);
|
||||
}
|
||||
|
||||
|
||||
int VP3_Decoder::decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf)
|
||||
{
|
||||
BYTE *data=(BYTE*)in;
|
||||
|
||||
if (!xim) return -1;
|
||||
|
||||
*out_type=NSV_MAKETYPE('Y','V','1','2');
|
||||
|
||||
if (vp3_postprocess != l_pp || vp3_targetcpu != l_tcpu)
|
||||
{
|
||||
l_pp=vp3_postprocess;
|
||||
l_tcpu=vp3_targetcpu;
|
||||
if (l_pp)
|
||||
{
|
||||
int v=l_tcpu;
|
||||
if (v < 1) v=1;
|
||||
if (v > 100) v=100;
|
||||
vp31_SetParameter(xim,1, v);
|
||||
vp31_SetParameter(xim,0, 9);
|
||||
}
|
||||
else
|
||||
{
|
||||
vp31_SetParameter(xim,1, 0);
|
||||
vp31_SetParameter(xim,0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
DXL_AlterXImageData( xim, data);
|
||||
DXL_SetXImageCSize(xim, in_len);
|
||||
|
||||
*is_kf=!(!in_len || data[0] > 0x7f);
|
||||
|
||||
*out=NULL;
|
||||
|
||||
if ((need_kf && !*is_kf) || !in_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!DXL_dxImageToVScreen( xim, NULL))
|
||||
{
|
||||
GetImageBufs(xim,&vidbufdec);
|
||||
if (m_uvflip)
|
||||
{
|
||||
YV12_PLANE tmp=vidbufdec.v;
|
||||
vidbufdec.v=vidbufdec.u;
|
||||
vidbufdec.u=tmp;
|
||||
}
|
||||
*out=&vidbufdec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
IVideoDecoder *VP3_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip)
|
||||
{
|
||||
if (fmt == NSV_MAKETYPE('V','P','3',' ') || fmt == NSV_MAKETYPE('V','P','3','1'))
|
||||
{
|
||||
*flip=1;
|
||||
return new VP3_Decoder(w,h,fmt == NSV_MAKETYPE('V','P','3',' '));
|
||||
}
|
||||
return NULL;
|
||||
}
|
11
Src/nsv/nsvplay/vp3stub.h
Normal file
11
Src/nsv/nsvplay/vp3stub.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _VP3STUB_H_
|
||||
#define _VP3STUB_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
extern int vp3_postprocess;
|
||||
extern int vp3_targetcpu;
|
||||
|
||||
IVideoDecoder *VP3_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip);
|
||||
|
||||
#endif
|
112
Src/nsv/nsvplay/vp5stub.cpp
Normal file
112
Src/nsv/nsvplay/vp5stub.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
#include <windows.h>
|
||||
#include "../nsvlib.h"
|
||||
#include "../dec_if.h"
|
||||
|
||||
#include "vfw.h"
|
||||
|
||||
class VP5_Decoder : public IVideoDecoder {
|
||||
public:
|
||||
VP5_Decoder(int w, int h);
|
||||
~VP5_Decoder();
|
||||
int decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf);
|
||||
void flush() { }
|
||||
|
||||
int m_err;
|
||||
|
||||
private:
|
||||
int width,height;
|
||||
BITMAPINFO vp5_bmo,vp5_bmi;
|
||||
HIC vp5_hic;
|
||||
unsigned char *vidbufdec;
|
||||
};
|
||||
|
||||
VP5_Decoder::VP5_Decoder(int w, int h)
|
||||
{
|
||||
width=w;
|
||||
height=h;
|
||||
m_err=0;
|
||||
vp5_hic=0;
|
||||
vidbufdec=(unsigned char*)malloc(sizeof(YV12_PLANES) + w*h*3/2);
|
||||
// init vp5 decode
|
||||
memset((void *) &vp5_bmi,0,sizeof(BITMAPINFO));
|
||||
memset((void *) &vp5_bmo,0,sizeof(BITMAPINFO));
|
||||
|
||||
vp5_bmi.bmiHeader.biCompression = mmioFOURCC('V','P','5','0');
|
||||
vp5_bmi.bmiHeader.biHeight=h;
|
||||
vp5_bmi.bmiHeader.biWidth =w;
|
||||
|
||||
vp5_bmo.bmiHeader.biCompression = mmioFOURCC('Y','V','1','2');
|
||||
vp5_bmo.bmiHeader.biHeight=h;
|
||||
vp5_bmo.bmiHeader.biWidth =w;
|
||||
vp5_bmo.bmiHeader.biBitCount = 12;
|
||||
|
||||
vp5_hic = ICOpen(ICTYPE_VIDEO, vp5_bmi.bmiHeader.biCompression, ICMODE_DECOMPRESS);
|
||||
vp5_bmo.bmiHeader.biHeight*=-1;
|
||||
if(!vp5_hic || ICERR_OK !=ICDecompressBegin(vp5_hic, &vp5_bmi, &vp5_bmo))
|
||||
{
|
||||
m_err=1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VP5_Decoder::~VP5_Decoder()
|
||||
{
|
||||
if (vp5_hic)
|
||||
{
|
||||
ICDecompressEnd(vp5_hic);
|
||||
ICClose(vp5_hic);
|
||||
}
|
||||
free(vidbufdec);
|
||||
}
|
||||
|
||||
|
||||
int VP5_Decoder::decode(int need_kf,
|
||||
void *in, int in_len,
|
||||
void **out, // out is set to a pointer to data
|
||||
unsigned int *out_type, // 'Y','V','1','2' is currently defined
|
||||
int *is_kf)
|
||||
{
|
||||
*out_type=NSV_MAKETYPE('Y','V','1','2');
|
||||
vp5_bmi.bmiHeader.biSizeImage = in_len;
|
||||
if(ICERR_OK == ICDecompress(vp5_hic,0,(BITMAPINFOHEADER *) &vp5_bmi, (char*)in,(BITMAPINFOHEADER *) &vp5_bmo, (char*)vidbufdec+sizeof(YV12_PLANES)))
|
||||
{
|
||||
*is_kf=!(!in_len || ((unsigned char *)in)[0] > 0x7f);
|
||||
if (need_kf && !*is_kf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
YV12_PLANES *image_vbd=(YV12_PLANES *)vidbufdec;
|
||||
image_vbd->y.baseAddr=(unsigned char *)(image_vbd+1);
|
||||
image_vbd->v.baseAddr=((unsigned char *)(image_vbd+1)) + width*height;
|
||||
image_vbd->u.baseAddr=((unsigned char *)(image_vbd+1)) + width*height*5/4;
|
||||
image_vbd->y.rowBytes=width;
|
||||
image_vbd->v.rowBytes=width/2;
|
||||
image_vbd->u.rowBytes=width/2;
|
||||
*out=(void*)vidbufdec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
IVideoDecoder *VP5_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip)
|
||||
{
|
||||
if (fmt == NSV_MAKETYPE('V','P','5','0'))
|
||||
{
|
||||
*flip=0;
|
||||
VP5_Decoder *a=new VP5_Decoder(w,h);
|
||||
if (a->m_err)
|
||||
{
|
||||
delete a;
|
||||
return NULL;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return NULL;
|
||||
}
|
8
Src/nsv/nsvplay/vp5stub.h
Normal file
8
Src/nsv/nsvplay/vp5stub.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _VP5STUB_H_
|
||||
#define _VP5STUB_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
IVideoDecoder *VP5_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip);
|
||||
|
||||
#endif
|
388
Src/nsv/nsvplay/wndmenu.h
Normal file
388
Src/nsv/nsvplay/wndmenu.h
Normal file
@ -0,0 +1,388 @@
|
||||
#ifndef _WNDMENU_H_
|
||||
#define _WNDMENU_H_
|
||||
|
||||
//need to define WNDMENU_CAPTION to the caption
|
||||
// you can define these to remove menu functionality
|
||||
//WNDMENU_NOABOUT // no about header
|
||||
//WNDMENU_NOVOLUME // no volume submenu
|
||||
//WNDMENU_NOINFO // no info submenu
|
||||
//WNDMENU_NOZOOM // no zoom 50/100/200/400
|
||||
//WNDMENU_NOZOOMFS // no zoom fullscreen
|
||||
//WNDMENU_NOOPTIONS // no options submenu
|
||||
//WNDMENU_NOPOSITIONSAVE // disables saving of position
|
||||
//WNDMENU_NOSUBTITLES // no subtitles submenu
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(x) ((x)<0?-(x):(x))
|
||||
#endif
|
||||
|
||||
|
||||
static void _ReadConfigItemInt(char *name, int *value)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Nullsoft\\NSVPlay",0,KEY_READ,&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD t,l=4;
|
||||
int a;
|
||||
if (RegQueryValueEx(hKey,name,NULL,&t,(unsigned char *)&a,&l ) == ERROR_SUCCESS && t == REG_DWORD)
|
||||
*value=a;
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
|
||||
static void _WriteConfigItemInt(char *name, int value)
|
||||
{
|
||||
HKEY hKey;
|
||||
if (RegCreateKey(HKEY_LOCAL_MACHINE,"Software\\Nullsoft\\NSVPlay",&hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueEx(hKey,name,0,REG_DWORD,(unsigned char*)&value,4);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
|
||||
static void _InsertString(HMENU hMenu, int pos, char *string, int id, int checked=0, int disabled=0)
|
||||
{
|
||||
MENUITEMINFO inf={sizeof(inf),MIIM_ID|MIIM_STATE|MIIM_TYPE,MFT_STRING,
|
||||
(checked?MFS_CHECKED:0) | (disabled?MFS_DISABLED:MFS_ENABLED), id,
|
||||
};
|
||||
inf.dwTypeData = string;
|
||||
|
||||
InsertMenuItem(hMenu,pos,TRUE,&inf);
|
||||
}
|
||||
|
||||
static void _InsertSep(HMENU hMenu, int pos)
|
||||
{
|
||||
MENUITEMINFO inf={sizeof(inf),MIIM_TYPE,MFT_SEPARATOR };
|
||||
InsertMenuItem(hMenu,pos,TRUE,&inf);
|
||||
}
|
||||
|
||||
static HMENU _InsertSub(HMENU hMenu, int pos, char *string)
|
||||
{
|
||||
MENUITEMINFO inf={sizeof(inf),MIIM_TYPE|MIIM_SUBMENU,MFT_STRING };
|
||||
inf.dwTypeData = string;
|
||||
inf.hSubMenu=CreatePopupMenu();
|
||||
InsertMenuItem(hMenu,pos,TRUE,&inf);
|
||||
return inf.hSubMenu;
|
||||
}
|
||||
|
||||
|
||||
#define MENUITEM_ABOUT 1
|
||||
#define MENUITEM_INFOBASE 10
|
||||
#define MENUITEM_VOLUMEBASE 100
|
||||
#define MENUITEM_VSYNC 120
|
||||
#define MENUITEM_ASPECTADJ 121
|
||||
#define MENUITEM_VOVERLAYS 122
|
||||
#define MENUITEM_VDDRAW 123
|
||||
#define MENUITEM_SOFTVOLMIX 124
|
||||
#define MENUITEM_ENABLESUBTITLES 125
|
||||
#define MENUITEM_SUBSIZEBASE 126 // 5 sizes
|
||||
|
||||
#define MENUITEM_ZOOM50 112
|
||||
#define MENUITEM_ZOOM100 113
|
||||
#define MENUITEM_ZOOM200 114
|
||||
#define MENUITEM_ZOOM400 115
|
||||
#define MENUITEM_ZOOMFS 116
|
||||
|
||||
#define MENUITEM_CLOSE 200
|
||||
|
||||
#define MENUITEM_SUBSLANGBASE 300
|
||||
|
||||
extern int g_audio_use_mixer;
|
||||
|
||||
LRESULT my_wndcallback(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (token)
|
||||
{
|
||||
parms *parm=(parms*)token;
|
||||
#ifndef WNDMENU_NOPOSITIONSAVE
|
||||
if (uMsg == WM_MOVE)
|
||||
{
|
||||
if (!parm->vidOut->is_fullscreen())
|
||||
{
|
||||
RECT r;
|
||||
GetWindowRect(hwnd,&r);
|
||||
_WriteConfigItemInt("xpos",r.left);
|
||||
_WriteConfigItemInt("ypos",r.top);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(uMsg==WM_SETCURSOR && parm->vidOut->is_fullscreen()) {
|
||||
SetCursor(NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (uMsg == WM_RBUTTONUP && !parm->vidOut->is_fullscreen())
|
||||
{
|
||||
int pos=0;
|
||||
HMENU hMenu=CreatePopupMenu();
|
||||
|
||||
#ifndef WNDMENU_NOABOUT
|
||||
_InsertString(hMenu,pos++,WNDMENU_CAPTION,MENUITEM_ABOUT);
|
||||
_InsertSep(hMenu,pos++);
|
||||
#endif
|
||||
#ifndef WNDMENU_NOINFO
|
||||
if (parm->decode)
|
||||
{
|
||||
char buf[1024];
|
||||
int subpos=0;
|
||||
int tmpid=MENUITEM_INFOBASE;
|
||||
HMENU sub=_InsertSub(hMenu,pos++,"Info");
|
||||
|
||||
{ // title
|
||||
char *v=parm->decode->getTitle();
|
||||
if (v && *v)
|
||||
{
|
||||
char *tmp=(char*)malloc(strlen(v)+32);
|
||||
wsprintf(tmp,"Title: %s",v);
|
||||
char *p=tmp;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '_') *p=' ';
|
||||
p++;
|
||||
}
|
||||
_InsertString(sub,subpos++,tmp,tmpid++);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ // length
|
||||
int lenms=parm->decode->getlen();
|
||||
if (lenms != ~0)
|
||||
{
|
||||
wsprintf(buf,"Length: %d:%02d",lenms/60000,(lenms/1000)%60);
|
||||
_InsertString(sub,subpos++,buf,tmpid++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ // codecs
|
||||
int a=(parm->decode->getBitrate()+500)/1000;
|
||||
unsigned int a2=parm->decode->getFileSize();
|
||||
if (a)
|
||||
{
|
||||
wsprintf(buf,"Bitrate: %dkbps",a);
|
||||
if (a2 && a2 != ~0)
|
||||
wsprintf(buf+strlen(buf)," (Total %u bytes)",a2);
|
||||
|
||||
_InsertString(sub,subpos++,buf,tmpid++);
|
||||
}
|
||||
else if (a2 && a2 != ~0)
|
||||
{
|
||||
wsprintf(buf,"Size: %u bytes",a2);
|
||||
_InsertString(sub,subpos++,buf,tmpid++);
|
||||
}
|
||||
|
||||
lstrcpy(buf,"Video: ");
|
||||
char *p=buf+strlen(buf);
|
||||
parm->decode->getVideoDesc(p);
|
||||
if (*p) _InsertString(sub,subpos++,buf,tmpid++);
|
||||
|
||||
lstrcpy(buf,"Audio: ");
|
||||
p=buf+strlen(buf);
|
||||
parm->decode->getAudioDesc(p);
|
||||
if (*p) _InsertString(sub,subpos++,buf,tmpid++);
|
||||
}
|
||||
|
||||
{
|
||||
const char *p=parm->decode->getServerHeader("Server");
|
||||
if (p && *p)
|
||||
{
|
||||
lstrcpy(buf,"Server: ");
|
||||
lstrcpyn(buf+strlen(buf),p,sizeof(buf)-strlen(buf)-2);
|
||||
_InsertString(sub,subpos++,buf,tmpid++);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //WNDMENU_NOINFO
|
||||
#ifndef WNDMENU_NOVOLUME
|
||||
if (parm->decode)
|
||||
{
|
||||
HMENU sub=_InsertSub(hMenu,pos++,"Volume");
|
||||
int cv=(parm->decode->getvolume()*100)/255;
|
||||
int x;
|
||||
for (x=0;x<=10;x++)
|
||||
{
|
||||
char buf[64];
|
||||
int a=100-x*10;
|
||||
wsprintf(buf,"%d%%",a);
|
||||
_InsertString(sub,x,buf,MENUITEM_VOLUMEBASE+x,cv >= a-5 && cv < a+5);
|
||||
}
|
||||
}
|
||||
#endif//WNDMENU_NOVOLUME
|
||||
#ifndef WNDMENU_NOOPTIONS
|
||||
if (parm->vidOut)
|
||||
{
|
||||
HMENU sub=_InsertSub(hMenu,pos++,"Options");
|
||||
int subpos=0;
|
||||
_InsertString(sub,subpos++,"Synchronize video to refresh",MENUITEM_VSYNC,!!parm->vidOut->vid_vsync);
|
||||
_InsertString(sub,subpos++,"Maintain video aspect ratio",MENUITEM_ASPECTADJ,!!parm->vidOut->vid_aspectadj);
|
||||
_InsertString(sub,subpos++,"Allow video overlay",MENUITEM_VOVERLAYS,!!parm->vidOut->vid_overlays);
|
||||
//_InsertString(sub,subpos++,"Allow DirectDraw acceleration",MENUITEM_VDDRAW,!!parm->vidOut->vid_ddraw);
|
||||
_InsertString(sub,subpos++,"Use software volume mixing",MENUITEM_SOFTVOLMIX,!g_audio_use_mixer);
|
||||
}
|
||||
#endif//WNDMENU_NOOPTIONS
|
||||
#if !defined(WNDMENU_NOZOOM) || !defined(WNDMENU_NOZOOMFS)
|
||||
if (parm->decode && parm->vidOut)
|
||||
{
|
||||
HMENU sub=_InsertSub(hMenu,pos++,"Zoom");
|
||||
int subpos=0;
|
||||
#ifndef WNDMENU_NOZOOM
|
||||
int ow,oh;
|
||||
int w=parm->decode->getWidth();
|
||||
int h=parm->decode->getHeight();
|
||||
parm->vidOut->getOutputSize(&ow,&oh);
|
||||
_InsertString(sub,subpos++,"50%",MENUITEM_ZOOM50,ABS(w/2-ow)<4);
|
||||
_InsertString(sub,subpos++,"100%",MENUITEM_ZOOM100,ABS(w-ow)<4);
|
||||
_InsertString(sub,subpos++,"200%",MENUITEM_ZOOM200,ABS(w*2-ow)<4);
|
||||
_InsertString(sub,subpos++,"400%",MENUITEM_ZOOM400,ABS(w/4-ow)<4);
|
||||
#ifndef WNDMENU_NOZOOMFS
|
||||
_InsertSep(sub,subpos++);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WNDMENU_NOZOOMFS
|
||||
_InsertString(sub,subpos++,"Fullscreen",MENUITEM_ZOOMFS,!!parm->vidOut->is_fullscreen());
|
||||
#endif//WNDMENU_NOZOOMFS
|
||||
}
|
||||
#endif//WNDMENU_NOZOOM||WNDMENU_NOZOOMFS
|
||||
|
||||
#ifndef WNDMENU_NOSUBTITLES
|
||||
if(parm->decode)
|
||||
{
|
||||
HMENU sub=_InsertSub(hMenu,pos++,"Subtitles");
|
||||
int subpos=0;
|
||||
_InsertString(sub,subpos++,"Enabled",MENUITEM_ENABLESUBTITLES,parm->decode->subsEnabled());
|
||||
_InsertSep(sub,subpos++);
|
||||
HMENU sizesub=_InsertSub(sub,subpos++,"Font size");
|
||||
int sizesubpos=0;
|
||||
int fontsize=parm->decode->getSubsFontSize();
|
||||
_InsertString(sizesub,sizesubpos++,"Largest",MENUITEM_SUBSIZEBASE,fontsize==20);
|
||||
_InsertString(sizesub,sizesubpos++,"Larger",MENUITEM_SUBSIZEBASE+1,fontsize==10);
|
||||
_InsertString(sizesub,sizesubpos++,"Medium",MENUITEM_SUBSIZEBASE+2,fontsize==0);
|
||||
_InsertString(sizesub,sizesubpos++,"Smaller",MENUITEM_SUBSIZEBASE+3,fontsize==-4);
|
||||
_InsertString(sizesub,sizesubpos++,"Smallest",MENUITEM_SUBSIZEBASE+4,fontsize==-8);
|
||||
HMENU langsub=_InsertSub(sub,subpos++,"Language");
|
||||
int langsubpos=0;
|
||||
for(int i=0;;i++) {
|
||||
const char *lang=parm->decode->getSubLanguage(i);
|
||||
if(!lang) break;
|
||||
_InsertString(langsub,langsubpos++,(char *)lang,MENUITEM_SUBSLANGBASE+i,i==parm->decode->getCurSubLanguage());
|
||||
}
|
||||
}
|
||||
#endif//WNDMENU_NOSUBTITLES
|
||||
|
||||
#ifndef WNDMENU_NOCLOSE
|
||||
_InsertSep(hMenu,pos++);
|
||||
_InsertString(hMenu,pos++,"E&xit\tAlt+F4",MENUITEM_CLOSE);
|
||||
#endif//WNDMENU_NOCLOSE
|
||||
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
int x=TrackPopupMenu(hMenu,TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,p.x,p.y,0,hwnd,NULL);
|
||||
DestroyMenu(hMenu);
|
||||
switch (x)
|
||||
{
|
||||
#ifndef WNDMENU_NOABOUT
|
||||
case MENUITEM_ABOUT:
|
||||
#ifdef _ABOUT_H_ // dont display the about box if do_about isn't there anyway
|
||||
do_about(hwnd);
|
||||
#endif
|
||||
break;
|
||||
#endif//WNDMENU_NOABOUT
|
||||
#ifndef WNDMENU_NOOPTIONS
|
||||
case MENUITEM_VOVERLAYS:
|
||||
_WriteConfigItemInt("overlays",parm->vidOut->vid_overlays=!parm->vidOut->vid_overlays);
|
||||
PostMessage(hwnd,WM_USER+0x1,0,0); //renegotiate surface
|
||||
break;
|
||||
case MENUITEM_VDDRAW:
|
||||
_WriteConfigItemInt("ddraw",parm->vidOut->vid_ddraw=!parm->vidOut->vid_ddraw);
|
||||
PostMessage(hwnd,WM_USER+0x1,0,0); //renegotiate surface
|
||||
break;
|
||||
case MENUITEM_ASPECTADJ:
|
||||
_WriteConfigItemInt("aspectadj",parm->vidOut->vid_aspectadj=!parm->vidOut->vid_aspectadj);
|
||||
PostMessage(hwnd,WM_TIMER,1,0);
|
||||
break;
|
||||
case MENUITEM_VSYNC:
|
||||
_WriteConfigItemInt("vsync",parm->vidOut->vid_vsync=!parm->vidOut->vid_vsync);
|
||||
break;
|
||||
case MENUITEM_SOFTVOLMIX:
|
||||
_WriteConfigItemInt("use_mixer",g_audio_use_mixer=!g_audio_use_mixer);
|
||||
parm->decode->setvolume(parm->decode->getvolume());
|
||||
break;
|
||||
#endif//WNDMENU_NOOPTIONS
|
||||
|
||||
#ifndef WNDMENU_NOZOOM
|
||||
case MENUITEM_ZOOM50:
|
||||
case MENUITEM_ZOOM100:
|
||||
case MENUITEM_ZOOM200:
|
||||
case MENUITEM_ZOOM400:
|
||||
if (parm->vidOut->is_fullscreen()) parm->vidOut->remove_fullscreen();
|
||||
{
|
||||
int w=parm->decode->getWidth();
|
||||
int h=parm->decode->getHeight();
|
||||
if (x == MENUITEM_ZOOM50) { w/=2; h/=2; }
|
||||
else if (x == MENUITEM_ZOOM200) { w*=2; h*=2; }
|
||||
else if (x == MENUITEM_ZOOM400) { w*=4; h*=4; }
|
||||
parm->vidOut->setOutputSize(w,h);
|
||||
|
||||
}
|
||||
break;
|
||||
#endif//WNDMENU_NOZOOM
|
||||
#ifndef WNDMENU_NOZOOMFS
|
||||
case MENUITEM_ZOOMFS:
|
||||
if (parm->vidOut->is_fullscreen()) parm->vidOut->remove_fullscreen();
|
||||
else parm->vidOut->fullscreen();
|
||||
break;
|
||||
#endif//WNDMENU_NOZOOMFS
|
||||
#ifndef WNDMENU_NOCLOSE
|
||||
case MENUITEM_CLOSE:
|
||||
SendMessage(hwnd,WM_CLOSE,0,0);
|
||||
break;
|
||||
#endif//WNDMENU_NOCLOSE
|
||||
#ifndef WNDMENU_NOSUBTITLES
|
||||
case MENUITEM_ENABLESUBTITLES:
|
||||
if(parm->decode) parm->decode->enableSubs(!parm->decode->subsEnabled());
|
||||
_WriteConfigItemInt("subtitles",parm->decode->subsEnabled());
|
||||
break;
|
||||
case MENUITEM_SUBSIZEBASE:
|
||||
case MENUITEM_SUBSIZEBASE+1:
|
||||
case MENUITEM_SUBSIZEBASE+2:
|
||||
case MENUITEM_SUBSIZEBASE+3:
|
||||
case MENUITEM_SUBSIZEBASE+4:
|
||||
if(parm->decode) {
|
||||
int sizes[]={20,10,0,-4,-8};
|
||||
int s=x-MENUITEM_SUBSIZEBASE;
|
||||
parm->decode->setSubsFontSize(sizes[s]);
|
||||
_WriteConfigItemInt("subtitles_size",parm->decode->getSubsFontSize());
|
||||
}
|
||||
break;
|
||||
#endif//WNDMENU_NOSUBTITLES
|
||||
default:
|
||||
#ifndef WNDMENU_NOVOLUME
|
||||
if (x >= MENUITEM_VOLUMEBASE && x <= MENUITEM_VOLUMEBASE+10)
|
||||
{
|
||||
int v=10-(x-MENUITEM_VOLUMEBASE);
|
||||
parm->decode->setvolume((v*255)/10);
|
||||
_WriteConfigItemInt("volume",parm->decode->getvolume());
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifndef WNDMENU_NOCLOSE
|
||||
case WM_CLOSE:
|
||||
DestroyWindow(hwnd);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#ifndef WNDMENU_NOSUBTITLES
|
||||
if(x>=MENUITEM_SUBSLANGBASE && x<=MENUITEM_SUBSLANGBASE+64) {
|
||||
parm->decode->setSubLanguage(x-MENUITEM_SUBSLANGBASE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
|
||||
#endif//_WNDMENU_H_
|
Reference in New Issue
Block a user