mirror of https://github.com/mpv-player/mpv
383 lines
13 KiB
C
383 lines
13 KiB
C
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#ifdef HAVE_MALLOC_H
|
|
#include <malloc.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include "mp_msg.h"
|
|
#include "help_mp.h"
|
|
|
|
#include "stream.h"
|
|
#include "demuxer.h"
|
|
|
|
#include "loader.h"
|
|
//#include "wine/mmreg.h"
|
|
#include "wine/vfw.h"
|
|
#include "wine/avifmt.h"
|
|
|
|
#include "codec-cfg.h"
|
|
#include "stheader.h"
|
|
|
|
#include "dll_init.h"
|
|
|
|
#include "libvo/img_format.h"
|
|
#include "linux/shmem.h"
|
|
|
|
extern int divx_quality;
|
|
|
|
// ACM audio and VfW video codecs initialization
|
|
// based on the avifile library [http://divx.euro.ru]
|
|
|
|
int init_acm_audio_codec(sh_audio_t *sh_audio){
|
|
HRESULT ret;
|
|
WAVEFORMATEX *in_fmt=sh_audio->wf;
|
|
unsigned long srcsize=0;
|
|
|
|
mp_msg(MSGT_WIN32,MSGL_V,"======= Win32 (ACM) AUDIO Codec init =======\n");
|
|
|
|
sh_audio->srcstream=NULL;
|
|
|
|
sh_audio->o_wf.nChannels=in_fmt->nChannels;
|
|
sh_audio->o_wf.nSamplesPerSec=in_fmt->nSamplesPerSec;
|
|
sh_audio->o_wf.nAvgBytesPerSec=2*sh_audio->o_wf.nSamplesPerSec*sh_audio->o_wf.nChannels;
|
|
sh_audio->o_wf.wFormatTag=WAVE_FORMAT_PCM;
|
|
sh_audio->o_wf.nBlockAlign=2*in_fmt->nChannels;
|
|
sh_audio->o_wf.wBitsPerSample=16;
|
|
sh_audio->o_wf.cbSize=0;
|
|
|
|
win32_codec_name = sh_audio->codec->dll;
|
|
ret=acmStreamOpen(&sh_audio->srcstream,(HACMDRIVER)NULL,
|
|
in_fmt,&sh_audio->o_wf,
|
|
NULL,0,0,0);
|
|
if(ret){
|
|
if(ret==ACMERR_NOTPOSSIBLE)
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,"ACM_Decoder: Unappropriate audio format\n");
|
|
else
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,"ACM_Decoder: acmStreamOpen error: %d", (int)ret);
|
|
sh_audio->srcstream=NULL;
|
|
return 0;
|
|
}
|
|
mp_msg(MSGT_WIN32,MSGL_V,"Audio codec opened OK! ;-)\n");
|
|
|
|
acmStreamSize(sh_audio->srcstream, in_fmt->nBlockAlign, &srcsize, ACM_STREAMSIZEF_SOURCE);
|
|
//if(verbose) printf("Audio ACM output buffer min. size: %ld (reported by codec)\n",srcsize);
|
|
srcsize*=2;
|
|
//if(srcsize<MAX_OUTBURST) srcsize=MAX_OUTBURST;
|
|
if(!srcsize){
|
|
mp_msg(MSGT_WIN32,MSGL_WARN,"Warning! ACM codec reports srcsize=0\n");
|
|
srcsize=16384;
|
|
}
|
|
// limit srcsize to 4-16kb
|
|
//while(srcsize && srcsize<4096) srcsize*=2;
|
|
//while(srcsize>16384) srcsize/=2;
|
|
sh_audio->audio_out_minsize=srcsize; // audio output min. size
|
|
mp_msg(MSGT_WIN32,MSGL_V,"Audio ACM output buffer min. size: %ld\n",srcsize);
|
|
|
|
acmStreamSize(sh_audio->srcstream, srcsize, &srcsize, ACM_STREAMSIZEF_DESTINATION);
|
|
sh_audio->audio_in_minsize=srcsize; // audio input min. size
|
|
mp_msg(MSGT_WIN32,MSGL_V,"Audio ACM input buffer min. size: %ld\n",srcsize);
|
|
|
|
if(srcsize<in_fmt->nBlockAlign) srcsize=in_fmt->nBlockAlign;
|
|
|
|
sh_audio->a_in_buffer_size=2*sh_audio->audio_in_minsize;
|
|
sh_audio->a_in_buffer=malloc(sh_audio->a_in_buffer_size);
|
|
sh_audio->a_in_buffer_len=0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int acm_decode_audio(sh_audio_t *sh_audio, void* a_buffer,int minlen,int maxlen){
|
|
ACMSTREAMHEADER ash;
|
|
HRESULT hr;
|
|
DWORD srcsize=0;
|
|
DWORD len=minlen;
|
|
acmStreamSize(sh_audio->srcstream,len , &srcsize, ACM_STREAMSIZEF_DESTINATION);
|
|
mp_msg(MSGT_WIN32,MSGL_DBG3,"acm says: srcsize=%ld (buffsize=%d) out_size=%d\n",srcsize,sh_audio->a_in_buffer_size,len);
|
|
|
|
if(srcsize<sh_audio->wf->nBlockAlign){
|
|
srcsize=sh_audio->wf->nBlockAlign;
|
|
acmStreamSize(sh_audio->srcstream, srcsize, &len, ACM_STREAMSIZEF_SOURCE);
|
|
if(len>maxlen) len=maxlen;
|
|
}
|
|
|
|
// if(srcsize==0) srcsize=((WAVEFORMATEX *)&sh_audio->o_wf_ext)->nBlockAlign;
|
|
if(srcsize>sh_audio->a_in_buffer_size) srcsize=sh_audio->a_in_buffer_size; // !!!!!!
|
|
if(sh_audio->a_in_buffer_len<srcsize){
|
|
sh_audio->a_in_buffer_len+=
|
|
demux_read_data(sh_audio->ds,&sh_audio->a_in_buffer[sh_audio->a_in_buffer_len],
|
|
srcsize-sh_audio->a_in_buffer_len);
|
|
}
|
|
mp_msg(MSGT_WIN32,MSGL_DBG3,"acm convert %d -> %d bytes\n",sh_audio->a_in_buffer_len,len);
|
|
memset(&ash, 0, sizeof(ash));
|
|
ash.cbStruct=sizeof(ash);
|
|
ash.fdwStatus=0;
|
|
ash.dwUser=0;
|
|
ash.pbSrc=sh_audio->a_in_buffer;
|
|
ash.cbSrcLength=sh_audio->a_in_buffer_len;
|
|
ash.pbDst=a_buffer;
|
|
ash.cbDstLength=len;
|
|
hr=acmStreamPrepareHeader(sh_audio->srcstream,&ash,0);
|
|
if(hr){
|
|
mp_msg(MSGT_WIN32,MSGL_V,"ACM_Decoder: acmStreamPrepareHeader error %d\n",(int)hr);
|
|
return -1;
|
|
}
|
|
hr=acmStreamConvert(sh_audio->srcstream,&ash,0);
|
|
if(hr){
|
|
mp_msg(MSGT_WIN32,MSGL_DBG2,"ACM_Decoder: acmStreamConvert error %d\n",(int)hr);
|
|
|
|
// return -1;
|
|
}
|
|
if(verbose>1)
|
|
mp_msg(MSGT_WIN32,MSGL_DBG2,"acm converted %d -> %d\n",ash.cbSrcLengthUsed,ash.cbDstLengthUsed);
|
|
if(ash.cbSrcLengthUsed>=sh_audio->a_in_buffer_len){
|
|
sh_audio->a_in_buffer_len=0;
|
|
} else {
|
|
sh_audio->a_in_buffer_len-=ash.cbSrcLengthUsed;
|
|
memcpy(sh_audio->a_in_buffer,&sh_audio->a_in_buffer[ash.cbSrcLengthUsed],sh_audio->a_in_buffer_len);
|
|
}
|
|
len=ash.cbDstLengthUsed;
|
|
hr=acmStreamUnprepareHeader(sh_audio->srcstream,&ash,0);
|
|
if(hr){
|
|
mp_msg(MSGT_WIN32,MSGL_V,"ACM_Decoder: acmStreamUnprepareHeader error %d\n",(int)hr);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
int init_vfw_video_codec(sh_video_t *sh_video,int ex){
|
|
HRESULT ret;
|
|
int yuv=0;
|
|
unsigned int outfmt=sh_video->codec->outfmt[sh_video->outfmtidx];
|
|
char *temp;
|
|
int temp_len;
|
|
int i;
|
|
|
|
mp_msg(MSGT_WIN32,MSGL_V,"======= Win32 (VFW) VIDEO Codec init =======\n");
|
|
|
|
memset(&sh_video->o_bih, 0, sizeof(BITMAPINFOHEADER));
|
|
sh_video->o_bih.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
win32_codec_name = sh_video->codec->dll;
|
|
// sh_video->hic = ICOpen( 0x63646976, sh_video->bih->biCompression, ICMODE_FASTDECOMPRESS);
|
|
sh_video->hic = ICOpen( 0x63646976, sh_video->bih->biCompression, ICMODE_DECOMPRESS);
|
|
if(!sh_video->hic){
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,"ICOpen failed! unknown codec / wrong parameters?\n");
|
|
return 0;
|
|
}
|
|
|
|
// sh_video->bih->biBitCount=32;
|
|
|
|
temp_len = ICDecompressGetFormatSize(sh_video->hic, sh_video->bih);
|
|
|
|
if (temp_len < sh_video->o_bih.biSize)
|
|
temp_len = sh_video->o_bih.biSize;
|
|
|
|
temp = malloc(temp_len);
|
|
printf("ICDecompressGetFormatSize ret: %d\n", temp_len);
|
|
|
|
#if 0
|
|
{
|
|
ICINFO icinfo;
|
|
ret = ICGetInfo(sh_video->hic, &icinfo, sizeof(ICINFO));
|
|
printf("%d - %d - %d\n", ret, icinfo.dwSize, sizeof(ICINFO));
|
|
printf("Compressor type: %.4x\n", icinfo.fccType);
|
|
printf("Compressor subtype: %.4x\n", icinfo.fccHandler);
|
|
printf("Compressor flags: %lu, version %lu, ICM version: %lu\n",
|
|
icinfo.dwFlags, icinfo.dwVersion, icinfo.dwVersionICM);
|
|
printf("Compressor name: %s\n", icinfo.szName);
|
|
printf("Compressor description: %s\n", icinfo.szDescription);
|
|
|
|
printf("Flags:");
|
|
if (icinfo.dwFlags & VIDCF_QUALITY)
|
|
printf(" quality");
|
|
if (icinfo.dwFlags & VIDCF_FASTTEMPORALD)
|
|
printf(" fast-decompr");
|
|
if (icinfo.dwFlags & VIDCF_QUALITYTIME)
|
|
printf(" temp-quality");
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
// Note: DivX.DLL overwrites 4 bytes _AFTER_ the o_bih header, so it corrupts
|
|
// the sh_video struct content. We call it with an 1024-byte temp space and
|
|
// then copy out the data we need:
|
|
memset(temp,0x77,temp_len);
|
|
|
|
ret = ICDecompressGetFormat(sh_video->hic, sh_video->bih, temp);
|
|
if(ret < 0){
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,"ICDecompressGetFormat failed: Error %d\n", (int)ret);
|
|
for (i=0; i < temp_len; i++) mp_msg(MSGT_WIN32, MSGL_DBG2, "%02x ", temp[i]);
|
|
return 0;
|
|
}
|
|
mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressGetFormat OK\n");
|
|
|
|
memcpy(&sh_video->o_bih,temp,sizeof(sh_video->o_bih));
|
|
|
|
if (temp_len > sizeof(sh_video->o_bih))
|
|
{
|
|
mp_msg(MSGT_WIN32, MSGL_V, "Extra info in o_bih (%d bytes)!\n",
|
|
temp_len-sizeof(sh_video->o_bih));
|
|
for(i=sizeof(sh_video->o_bih);i<temp_len;i++) mp_msg(MSGT_WIN32, MSGL_DBG2, "%02X ",temp[i]);
|
|
}
|
|
free(temp);
|
|
// printf("ICM_DECOMPRESS_QUERY=0x%X",ICM_DECOMPRESS_QUERY);
|
|
|
|
// sh_video->o_bih.biWidth=sh_video->bih.biWidth;
|
|
// sh_video->o_bih.biCompression = 0x32315659; // mmioFOURCC('U','Y','V','Y');
|
|
// ret=ICDecompressGetFormatSize(sh_video->hic,&sh_video->o_bih);
|
|
// sh_video->o_bih.biCompression = 3; //0x32315659;
|
|
// sh_video->o_bih.biCompression = mmioFOURCC('U','Y','V','Y');
|
|
// sh_video->o_bih.biCompression = mmioFOURCC('U','Y','V','Y');
|
|
// sh_video->o_bih.biCompression = mmioFOURCC('Y','U','Y','2');
|
|
// sh_video->o_bih.biPlanes=3;
|
|
// sh_video->o_bih.biBitCount=16;
|
|
|
|
#if 0
|
|
// workaround for pegasus MJPEG:
|
|
if(!sh_video->o_bih.biWidth) sh_video->o_bih.biWidth=sh_video->bih->biWidth;
|
|
if(!sh_video->o_bih.biHeight) sh_video->o_bih.biHeight=sh_video->bih->biHeight;
|
|
if(!sh_video->o_bih.biPlanes) sh_video->o_bih.biPlanes=sh_video->bih->biPlanes;
|
|
#endif
|
|
|
|
switch (outfmt) {
|
|
|
|
/* planar format */
|
|
case IMGFMT_YV12:
|
|
case IMGFMT_I420:
|
|
case IMGFMT_IYUV:
|
|
sh_video->o_bih.biBitCount=12;
|
|
yuv=1;
|
|
break;
|
|
|
|
/* packed format */
|
|
case IMGFMT_YUY2:
|
|
case IMGFMT_UYVY:
|
|
case IMGFMT_YVYU:
|
|
sh_video->o_bih.biBitCount=16;
|
|
yuv=1;
|
|
break;
|
|
|
|
/* rgb/bgr format */
|
|
case IMGFMT_RGB8:
|
|
case IMGFMT_BGR8:
|
|
sh_video->o_bih.biBitCount=8;
|
|
break;
|
|
|
|
case IMGFMT_RGB15:
|
|
case IMGFMT_RGB16:
|
|
case IMGFMT_BGR15:
|
|
case IMGFMT_BGR16:
|
|
sh_video->o_bih.biBitCount=16;
|
|
break;
|
|
|
|
case IMGFMT_RGB24:
|
|
case IMGFMT_BGR24:
|
|
sh_video->o_bih.biBitCount=24;
|
|
break;
|
|
|
|
case IMGFMT_RGB32:
|
|
case IMGFMT_BGR32:
|
|
sh_video->o_bih.biBitCount=32;
|
|
break;
|
|
|
|
default:
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,"unsupported image format: 0x%x\n", outfmt);
|
|
return 0;
|
|
}
|
|
|
|
sh_video->o_bih.biSizeImage = sh_video->o_bih.biWidth * sh_video->o_bih.biHeight * (sh_video->o_bih.biBitCount/8);
|
|
|
|
if(!(sh_video->codec->outflags[sh_video->outfmtidx]&CODECS_FLAG_FLIP)) {
|
|
sh_video->o_bih.biHeight=-sh_video->bih->biHeight; // flip image!
|
|
}
|
|
|
|
if(yuv && !(sh_video->codec->outflags[sh_video->outfmtidx] & CODECS_FLAG_YUVHACK))
|
|
sh_video->o_bih.biCompression = outfmt;
|
|
else
|
|
sh_video->o_bih.biCompression = 0;
|
|
|
|
if(verbose) {
|
|
printf("Starting decompression, format:\n");
|
|
printf(" biSize %ld\n", sh_video->bih->biSize);
|
|
printf(" biWidth %ld\n", sh_video->bih->biWidth);
|
|
printf(" biHeight %ld\n", sh_video->bih->biHeight);
|
|
printf(" biPlanes %d\n", sh_video->bih->biPlanes);
|
|
printf(" biBitCount %d\n", sh_video->bih->biBitCount);
|
|
printf(" biCompression 0x%lx ('%.4s')\n", sh_video->bih->biCompression, (char *)&sh_video->bih->biCompression);
|
|
printf(" biSizeImage %ld\n", sh_video->bih->biSizeImage);
|
|
printf("Dest fmt:\n");
|
|
printf(" biSize %ld\n", sh_video->o_bih.biSize);
|
|
printf(" biWidth %ld\n", sh_video->o_bih.biWidth);
|
|
printf(" biHeight %ld\n", sh_video->o_bih.biHeight);
|
|
printf(" biPlanes %d\n", sh_video->o_bih.biPlanes);
|
|
printf(" biBitCount %d\n", sh_video->o_bih.biBitCount);
|
|
printf(" biCompression 0x%lx ('%.4s')\n", sh_video->o_bih.biCompression, (char *)&sh_video->o_bih.biCompression);
|
|
printf(" biSizeImage %ld\n", sh_video->o_bih.biSizeImage);
|
|
}
|
|
|
|
ret = ex ?
|
|
ICDecompressQueryEx(sh_video->hic, sh_video->bih, &sh_video->o_bih) :
|
|
ICDecompressQuery(sh_video->hic, sh_video->bih, &sh_video->o_bih);
|
|
if(ret){
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,"ICDecompressQuery failed: Error %d\n", (int)ret);
|
|
// return 0;
|
|
} else
|
|
mp_msg(MSGT_WIN32,MSGL_V,"ICDecompressQuery OK\n");
|
|
|
|
ret = ex ?
|
|
ICDecompressBeginEx(sh_video->hic, sh_video->bih, &sh_video->o_bih) :
|
|
ICDecompressBegin(sh_video->hic, sh_video->bih, &sh_video->o_bih);
|
|
if(ret){
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,"ICDecompressBegin failed: Error %d\n", (int)ret);
|
|
return 0;
|
|
}
|
|
|
|
sh_video->our_out_buffer = (char*)memalign(64,sh_video->o_bih.biSizeImage);
|
|
if(!sh_video->our_out_buffer){
|
|
mp_msg(MSGT_WIN32,MSGL_ERR,MSGTR_NoMemForDecodedImage, sh_video->o_bih.biSizeImage);
|
|
return 0;
|
|
}
|
|
|
|
if(yuv && sh_video->codec->outflags[sh_video->outfmtidx] & CODECS_FLAG_YUVHACK)
|
|
sh_video->o_bih.biCompression = outfmt;
|
|
|
|
// avi_header.our_in_buffer=malloc(avi_header.video.dwSuggestedBufferSize); // FIXME!!!!
|
|
|
|
ICSendMessage(sh_video->hic, ICM_USER+80, (long)(&divx_quality) ,NULL);
|
|
|
|
mp_msg(MSGT_WIN32,MSGL_V,"VIDEO CODEC Init OK!!! ;-)\n");
|
|
return 1;
|
|
}
|
|
|
|
int vfw_set_postproc(sh_video_t* sh_video,int quality){
|
|
// Works only with opendivx/divx4 based DLL
|
|
return ICSendMessage(sh_video->hic, ICM_USER+80, (long)(&quality) ,NULL);
|
|
}
|
|
|
|
int vfw_decode_video(sh_video_t* sh_video,void* start,int in_size,int drop_frame,int ex){
|
|
HRESULT ret;
|
|
|
|
sh_video->bih->biSizeImage = in_size;
|
|
|
|
if(ex)
|
|
ret = ICDecompressEx(sh_video->hic,
|
|
( (sh_video->ds->flags&1) ? 0 : ICDECOMPRESS_NOTKEYFRAME ) |
|
|
( (drop_frame==2 && !(sh_video->ds->flags&1))?(ICDECOMPRESS_HURRYUP|ICDECOMPRESS_PREROL):0 ) ,
|
|
sh_video->bih, start,
|
|
&sh_video->o_bih,
|
|
drop_frame ? 0 : sh_video->our_out_buffer);
|
|
else
|
|
ret = ICDecompress(sh_video->hic,
|
|
( (sh_video->ds->flags&1) ? 0 : ICDECOMPRESS_NOTKEYFRAME ) |
|
|
( (drop_frame==2 && !(sh_video->ds->flags&1))?(ICDECOMPRESS_HURRYUP|ICDECOMPRESS_PREROL):0 ) ,
|
|
sh_video->bih, start,
|
|
&sh_video->o_bih,
|
|
drop_frame ? 0 : sh_video->our_out_buffer);
|
|
|
|
return (int)ret;
|
|
}
|
|
|