#include "config.h" #include #ifdef HAVE_MALLOC_H #include #endif #include #include #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" #ifdef USE_LIBVO2 #include "libvo2/img_format.h" #else #include "libvo/img_format.h" #endif #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(srcsize16384) 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(srcsizenBlockAlign) 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(srcsizewf->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_lena_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); // memcpy(temp,sh_video->bih,sizeof(BITMAPINFOHEADER)); // sh_video->o_bih.biSize = 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);io_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; }