[MPlayer-dev-eng] [PATCH] Support CineForm DirectShow codec

Steinar H. Gunderson sgunderson at bigfoot.com
Fri Jan 8 00:23:20 CET 2010


[Cc-ing others who have expressed interest in CineForm on the list before.]

Hi,

Here is a patch to support CineForm, a relatively popular HD intermediate
codec, in MPlayer. It's a bit raw (segfaults on exit, for one), but at least
it's a usable starting point. The decoder binary is available for free from
www.cineform.com (Windows installer download); others have posted a sample
earlier at

  http://www.royaltyfreehdtv.com/footage/MT_BeartoothHighway_1min_Cineform.avi

Relevant changes:

 - codecs.conf entry, of course. Note that the codec outputs BGR24 for some
   reason; don't ask me why. (More about colorspace below.)
 - A few new Win32 calls. Most of these are stubs or very simple.
 - DirectShow specifies that a filter (codec) can expect JoinFilterGraph
   to be called, and store a reference to the graph manager. CF uses this
   to ask the graph manager for the current time if supported. To this end,
   I've implemented a dummy GraphManager; it's extremely bare-bones (it
   doesn't even have a vtable outside the IUnknown vtable), but all CF wants
   anyway is to ask if it supports IMediaSeeking, and when it doesn't it
   continues happily on.
 - The codec doesn't support RGB24 by default (it's some kind of UI setting),
   and this seems to cause all sorts of problems for MPlayer's dshow
   emulation. The easiest way to fix this is to tell the codec there's
   a HKEY_CURRENT_USER\Software\CineForm\DecoderProperties key with
   setting PixelFormats = (some bitmask), at which point it will happily
   output tons of colorspaces (it seems to support v210, V210, RG30,
   DPX0, A2R10G10B10, A2B10G10R10, BYR1, BYR2, BYR3, RGB1 (!), RGB4,
   RGB8, RGB565, RGB555, RGB24, RGB32 and ARGB32, and possibly more).
   It also expects to read a hex value "Resolution" in the same registry
   key; otherwise it will never try PixelFormats.
 - CF wants to read and write some files ending in .colr, .col1 and .col2
   (I haven't checked for what), so I've added them to the CreateFileA
   whitelist.

Caveats:

 - The codec crashes on exit. I'm not sure why.
 - The preview mode (half-resolution, easier on the CPU -- this is a 
   wavelet codec) which you can activate by setting the Resolution registry
   value to 0x3e9 is not properly supported (in particular, there's no user
   knob to set it).
 - CineForm supports different colorspaces, among them A2R10G10B10
   (perhaps interesting for very high-def users) and various YUV colorspaces,
   but the dshow loader doesn't seem to get much sense of it, so I haven't
   done anything for it.
 - The codec has a concept of LUT files that can do various forms of
   colorspace correction etc. live during playback. (This depends on
   a few more registry entries, for one.) I haven't made any effort to
   support this, but I don't think you need it to play typical files.
 - I don't own a copy of the CineForm encoder, so I have no idea if it would
   be supported for encode.

Comments welcome, of course.

/* Steinar */

diff -Nur orig/mplayer-export-2010-01-02/etc/codecs.conf mplayer-export-2010-01-02/etc/codecs.conf
--- orig/mplayer-export-2010-01-02/etc/codecs.conf	2010-01-01 00:45:07.000000000 +0100
+++ mplayer-export-2010-01-02/etc/codecs.conf	2010-01-06 21:06:17.000000000 +0100
@@ -1911,6 +1911,15 @@
   dll "aslcodec_vfw.dll"
   out BGR24 flip
 
+videocodec cineformhd
+  info "CineForm HD"
+  status working
+  fourcc CFHD
+  driver dshow
+  dll "CFDecode2.ax"
+  guid 0xAD83011E, 0x01d1, 0x4623, 0x91, 0xfd, 0x6b, 0x75, 0xf1, 0x83, 0xc5, 0xa9
+  out BGR24
+
 videocodec LEADMW20
   info "Lead CMW wavelet 2.0"
   status working
diff -Nur orig/mplayer-export-2010-01-02/loader/dshow/DS_Filter.c mplayer-export-2010-01-02/loader/dshow/DS_Filter.c
--- orig/mplayer-export-2010-01-02/loader/dshow/DS_Filter.c	2009-05-13 04:58:57.000000000 +0200
+++ mplayer-export-2010-01-02/loader/dshow/DS_Filter.c	2010-01-06 20:43:29.000000000 +0100
@@ -7,6 +7,7 @@
 #include "DS_Filter.h"
 #include "drv.h"
 #include "com.h"
+#include "graph.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -125,6 +126,7 @@
 //    char eb[250];
     const char* em = NULL;
     MemAllocator* tempAll;
+    FilterGraph* graph;
     ALLOCATOR_PROPERTIES props,props1;
     DS_Filter* This = malloc(sizeof(DS_Filter));
     if (!This)
@@ -143,6 +145,7 @@
 	to CoCreateInstance(...,&IID_IMemoryAllocator,...) from binary codec.
     */
     tempAll=MemAllocatorCreate();
+    graph=FilterGraphCreate();
     This->m_pFilter = NULL;
     This->m_pInputPin = NULL;
     This->m_pOutputPin = NULL;
@@ -199,6 +202,9 @@
 	    em = "object does not provide IBaseFilter interface";
             break;
 	}
+
+	result = This->m_pFilter->vt->JoinFilterGraph(This->m_pFilter, (IFilterGraph*)graph, (short *)"F\0i\0l\0t\0e\0r\0");
+
 	// enumerate pins
 	result = This->m_pFilter->vt->EnumPins(This->m_pFilter, &enum_pins);
 	if (result || !enum_pins)
diff -Nur orig/mplayer-export-2010-01-02/loader/dshow/graph.c mplayer-export-2010-01-02/loader/dshow/graph.c
--- orig/mplayer-export-2010-01-02/loader/dshow/graph.c	1970-01-01 01:00:00.000000000 +0100
+++ mplayer-export-2010-01-02/loader/dshow/graph.c	2010-01-06 21:10:04.000000000 +0100
@@ -0,0 +1,77 @@
+/*
+ * Modified for use with MPlayer, detailed changelog at
+ * http://svn.mplayerhq.hu/mplayer/trunk/
+ */
+
+#include "config.h"
+#include "graph.h"
+#include "com.h"
+#include "wine/winerror.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int GraphKeeper = 0;
+
+static long FilterGraph_CreateGraph(GUID* clsid, const GUID* iid, void** ppv)
+{
+    IFilterGraph* p;
+    int result;
+    if (!ppv)
+	return -1;
+    *ppv = 0;
+    if (memcmp(clsid, &CLSID_FilterGraph, sizeof(GUID)))
+	return -1;
+
+    p = (IFilterGraph*) FilterGraphCreate();
+    result = p->vt->QueryInterface((IUnknown*)p, iid, ppv);
+    p->vt->Release((IUnknown*)p);
+
+    return result;
+}
+
+static void FilterGraph_Destroy(FilterGraph* This)
+{
+    Debug printf("FilterGraph_Destroy(%p) called  (%d, %d)\n", This, This->refcount, GraphKeeper);
+#ifdef WIN32_LOADER
+    if (--GraphKeeper == 0)
+	UnregisterComClass(&CLSID_FilterGraph, FilterGraph_CreateGraph);
+#endif
+    free(This->vt);
+    free(This);
+}
+
+IMPLEMENT_IUNKNOWN(FilterGraph)
+
+FilterGraph* FilterGraphCreate()
+{
+    FilterGraph* This = (FilterGraph*) malloc(sizeof(FilterGraph));
+
+    if (!This)
+        return NULL;
+
+    Debug printf("FilterGraphCreate() called -> %p\n", This);
+
+    This->refcount = 1;
+
+    This->vt = (IFilterGraph_vt*) malloc(sizeof(IFilterGraph_vt));
+
+    if (!This->vt)
+    {
+        free(This);
+	return NULL;
+    }
+
+    This->vt->QueryInterface = FilterGraph_QueryInterface;
+    This->vt->AddRef = FilterGraph_AddRef;
+    This->vt->Release = FilterGraph_Release;
+
+    This->interfaces[0]=IID_IUnknown;
+    This->interfaces[1]=IID_IFilterGraph;
+
+#ifdef WIN32_LOADER
+    if (GraphKeeper++ == 0)
+	RegisterComClass(&CLSID_FilterGraph, FilterGraph_CreateGraph);
+#endif
+
+    return This;
+}
diff -Nur orig/mplayer-export-2010-01-02/loader/dshow/graph.h mplayer-export-2010-01-02/loader/dshow/graph.h
--- orig/mplayer-export-2010-01-02/loader/dshow/graph.h	1970-01-01 01:00:00.000000000 +0100
+++ mplayer-export-2010-01-02/loader/dshow/graph.h	2010-01-06 01:11:50.000000000 +0100
@@ -0,0 +1,20 @@
+#ifndef MPLAYER_GRAPH_H
+#define MPLAYER_GRAPH_H
+
+#include "interfaces.h"
+#include "cmediasample.h"
+
+typedef struct FilterGraph FilterGraph;
+
+struct FilterGraph
+{
+    IFilterGraph_vt* vt;
+    DECLARE_IUNKNOWN();
+    GUID interfaces[2];
+
+    // TODO: Add real methods here
+};
+
+FilterGraph* FilterGraphCreate(void);
+
+#endif /* MPLAYER_GRAPH_H */
diff -Nur orig/mplayer-export-2010-01-02/loader/dshow/guids.c mplayer-export-2010-01-02/loader/dshow/guids.c
--- orig/mplayer-export-2010-01-02/loader/dshow/guids.c	2002-11-26 22:00:20.000000000 +0100
+++ mplayer-export-2010-01-02/loader/dshow/guids.c	2010-01-06 01:15:33.000000000 +0100
@@ -13,6 +13,8 @@
     {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
 const GUID IID_IEnumMediaTypes={0x89c31040, 0x846b, 0x11ce,
     {0x97, 0xd3, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
+const GUID IID_IFilterGraph={0x56a8689f, 0x0ad4, 0x11ce,
+    {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
 const GUID IID_IMemInputPin={0x56a8689d, 0x0ad4, 0x11ce,
     {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
 const GUID IID_IMemAllocator={0x56a8689c, 0x0ad4, 0x11ce,
@@ -64,6 +66,8 @@
     {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
 const GUID MEDIASUBTYPE_IF09={0x39304649, 0x0000, 0x0010,
     {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
+const GUID CLSID_FilterGraph={0xe436ebb3, 0x524f, 0x11ce,
+    {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
 const GUID CLSID_MemoryAllocator={0x1e651cc0, 0xb199, 0x11d0,
     {0x82, 0x12, 0x00, 0xc0, 0x4f, 0xc3, 0x2c, 0x45}};
 const GUID IID_DivxHidden={0x598eba01, 0xb49a, 0x11d2,
diff -Nur orig/mplayer-export-2010-01-02/loader/dshow/guids.h mplayer-export-2010-01-02/loader/dshow/guids.h
--- orig/mplayer-export-2010-01-02/loader/dshow/guids.h	2008-02-23 15:50:55.000000000 +0100
+++ mplayer-export-2010-01-02/loader/dshow/guids.h	2010-01-06 20:40:34.000000000 +0100
@@ -46,6 +46,7 @@
 extern const GUID IID_IBaseFilter;
 extern const GUID IID_IEnumPins;
 extern const GUID IID_IEnumMediaTypes;
+extern const GUID IID_IFilterGraph;
 extern const GUID IID_IMemInputPin;
 extern const GUID IID_IMemAllocator;
 extern const GUID IID_IMediaSample;
@@ -54,6 +55,7 @@
 extern const GUID CLSID_DivxDecompressorCF;
 extern const GUID IID_IDivxFilterInterface;
 extern const GUID CLSID_IV50_Decoder;
+extern const GUID CLSID_FilterGraph;
 extern const GUID CLSID_MemoryAllocator;
 extern const GUID MEDIATYPE_Video;
 extern const GUID GUID_NULL;
diff -Nur orig/mplayer-export-2010-01-02/loader/dshow/interfaces.h mplayer-export-2010-01-02/loader/dshow/interfaces.h
--- orig/mplayer-export-2010-01-02/loader/dshow/interfaces.h	2008-02-23 15:50:55.000000000 +0100
+++ mplayer-export-2010-01-02/loader/dshow/interfaces.h	2010-01-06 01:07:14.000000000 +0100
@@ -13,7 +13,15 @@
 /*    Sh*t. MSVC++ and g++ use different methods of storing vtables.    */
 
 typedef struct IReferenceClock IReferenceClock;
+
 typedef struct IFilterGraph IFilterGraph;
+typedef struct IFilterGraph_vt
+{
+    INHERIT_IUNKNOWN();
+
+    // TODO: Implement
+} IFilterGraph_vt;
+struct IFilterGraph { IFilterGraph_vt* vt; };
 
 typedef struct IBaseFilter IBaseFilter;
 
diff -Nur orig/mplayer-export-2010-01-02/loader/registry.c mplayer-export-2010-01-02/loader/registry.c
--- orig/mplayer-export-2010-01-02/loader/registry.c	2009-05-04 19:35:26.000000000 +0200
+++ mplayer-export-2010-01-02/loader/registry.c	2010-01-06 21:09:22.000000000 +0100
@@ -385,7 +385,7 @@
     if(handle==head)
 	head=head->prev;
     free(handle);
-    return 1;
+    return 0;
 }
 
 long __stdcall RegQueryValueExA(long key, const char* value, int* reserved, int* type, int* data, int* count)
@@ -396,6 +396,18 @@
     if(!regs)
 	init_registry();
 
+    // Hacks for CineForm.
+    if (value) {
+      if (strcmp(value, "Resolution") == 0) {
+        *data = 0x3e8;
+        return 0;
+      }
+      if (strcmp(value, "PixelFormats") == 0) {
+        *data = 0xffff;
+        return 0;
+      }
+    }
+
     c=build_keyname(key, value);
     if (!c)
 	return 1;
diff -Nur orig/mplayer-export-2010-01-02/loader/win32.c mplayer-export-2010-01-02/loader/win32.c
--- orig/mplayer-export-2010-01-02/loader/win32.c	2009-10-10 11:27:22.000000000 +0200
+++ mplayer-export-2010-01-02/loader/win32.c	2010-01-06 21:47:06.000000000 +0100
@@ -562,6 +562,7 @@
 #define	MODULE_HANDLE_msvcrt	((HMODULE)0x126)
 #define	MODULE_HANDLE_ole32	((HMODULE)0x127)
 #define	MODULE_HANDLE_winmm	((HMODULE)0x128)
+#define	MODULE_HANDLE_psapi	((HMODULE)0x129)
 
 static HMODULE WINAPI expGetModuleHandleA(const char* name)
 {
@@ -1133,6 +1134,10 @@
     return result;
 }
 
+static WIN_BOOL WINAPI expIsDebuggerPresent(void)
+{
+    return 0;
+}
 
 static long WINAPI expGetVersion(void)
 {
@@ -2269,6 +2274,21 @@
     return result;
 }
 
+static int WINAPI expGetModuleBaseNameA(int process, int module, char* s, int len)
+{
+    int result = 0;
+   
+    if (len >= 12) {
+	strcpy(s, "aviplay.dll");
+	result = 11;
+    }
+
+    dbgprintf("GetModuleBaseNameA(0x%x, 0x%x, 0x%x, %d) => %d\n",
+        process, module, s, len, result);
+
+    return result;
+}
+
 static int WINAPI expSetUnhandledExceptionFilter(void* filter)
 {
     dbgprintf("SetUnhandledExceptionFilter(0x%x) => 1\n", filter);
@@ -2329,6 +2349,8 @@
 	return MODULE_HANDLE_ole32;
     if (strcasecmp(name, "winmm.dll") == 0 || strcasecmp(name, "winmm") == 0)
 	return MODULE_HANDLE_winmm;
+    if (strcasecmp(name, "psapi.dll") == 0 || strcasecmp(name, "psapi") == 0)
+	return MODULE_HANDLE_psapi;
 
     result=LoadLibraryA(name);
     dbgprintf("Returned LoadLibraryA(0x%x='%s'), def_path=%s => 0x%x\n", name, name, def_path, result);
@@ -2371,6 +2393,8 @@
 	result=LookupExternalByName("ole32.dll", name); break;
     case MODULE_HANDLE_winmm:
 	result=LookupExternalByName("winmm.dll", name); break;
+    case MODULE_HANDLE_psapi:
+	result=LookupExternalByName("psapi.dll", name); break;
     default:
 	result=GetProcAddress(mod, name);
     }
@@ -3518,7 +3542,7 @@
 	free(tmp);
 	return result;
     }
-    if (strstr(cs1, "vp3") || strstr(cs1, ".fpf"))
+    if (strstr(cs1, "vp3") || strstr(cs1, ".fpf") || strstr(cs1, ".col"))
     {
 	int r;
 	int flg = 0;
@@ -4543,6 +4567,12 @@
     return TRUE;
 }
 
+static void WINAPI expTerminateProcess( DWORD process, DWORD status )
+{
+    printf("EXIT - process %ld code %ld\n", process, status);
+    exit(status);
+}
+
 static void WINAPI expExitProcess( DWORD status )
 {
     printf("EXIT - code %ld\n",status);
@@ -4592,6 +4622,27 @@
 //    dbgprintf("ntohl(%x) => %x\n", netlong, ntohl(netlong));
     return ntohl(netlong);
 }
+
+static char* WINAPI expSysAllocStringLen(char *pch, unsigned cch)
+{
+    char *str;
+    dbgprintf("SysAllocStringLen('%s', %d)\n", pch, cch);
+    str = (char *)malloc(cch + sizeof(unsigned) + 1);
+    if (pch != NULL) {
+        memcpy(str + sizeof(unsigned), pch, cch);
+    }
+    *(str + sizeof(unsigned) + cch) = 0;
+    memcpy(str, &cch, sizeof(cch));
+    return str + sizeof(unsigned);
+}
+
+static void WINAPI expSysFreeString(char *str)
+{
+    if (str) {
+        free(str - sizeof(unsigned));
+    }
+}
+
 static void WINAPI expVariantInit(void* p)
 {
     printf("InitCommonControls called!\n");
@@ -4846,6 +4897,20 @@
     return p;
 }
 
+static DWORD WINAPI expGetThreadLocale(void)
+{
+    return 0;
+}
+
+static DWORD WINAPI expGetLocaleInfoA(DWORD locale, DWORD lctype, char* lpLCData, int cchData)
+{
+    if (lctype == 0x1004) {  // LOCALE_IDEFAULTANSICODEPAGE
+       strcpy(lpLCData, "437");
+       return 0;
+    }
+    return 1;
+}
+
 struct exports
 {
     char name[64];
@@ -4997,6 +5062,7 @@
     FF(GetFullPathNameA,-1)
     FF(SetErrorMode, -1)
     FF(IsProcessorFeaturePresent, -1)
+    FF(IsDebuggerPresent, -1)
     FF(GetProcessAffinityMask, -1)
     FF(InterlockedExchange, -1)
     FF(InterlockedCompareExchange, -1)
@@ -5017,12 +5083,15 @@
     FF(GlobalMemoryStatus,-1)
     FF(GetThreadPriority,-1)
     FF(SetThreadPriority,-1)
+    FF(TerminateProcess,-1)
     FF(ExitProcess,-1)
     {"LoadLibraryExA", -1, (void*)&LoadLibraryExA},
     FF(SetThreadIdealProcessor,-1)
     FF(SetProcessAffinityMask, -1)
     FF(EncodePointer, -1)
     FF(DecodePointer, -1)
+    FF(GetThreadLocale, -1)
+    FF(GetLocaleInfoA, -1)
     UNDEFF(FlsAlloc, -1)
     UNDEFF(FlsGetValue, -1)
     UNDEFF(FlsSetValue, -1)
@@ -5106,6 +5175,9 @@
     FF(waveOutGetNumDevs, -1)
 #endif
 };
+struct exports exp_psapi[]={
+    FF(GetModuleBaseNameA, -1)
+};
 struct exports exp_user32[]={
     FF(LoadIconA,-1)
     FF(LoadStringA, -1)
@@ -5220,6 +5292,8 @@
     FF(MoInitMediaType, -1)
 };
 struct exports exp_oleaut32[]={
+    FF(SysAllocStringLen, 4)
+    FF(SysFreeString, 6)
     FF(VariantInit, 8)
 #ifdef QTX
     FF(SysStringByteLen, 149)
@@ -5302,6 +5376,7 @@
     LL(kernel32)
     LL(msvcrt)
     LL(winmm)
+    LL(psapi)
     LL(user32)
     LL(advapi32)
     LL(gdi32)
diff -Nur orig/mplayer-export-2010-01-02/Makefile mplayer-export-2010-01-02/Makefile
--- orig/mplayer-export-2010-01-02/Makefile	2009-12-31 19:25:35.000000000 +0100
+++ mplayer-export-2010-01-02/Makefile	2010-01-06 20:42:34.000000000 +0100
@@ -312,6 +312,7 @@
                                         loader/dshow/DS_VideoDecoder.c \
                                         loader/dshow/allocator.c \
                                         loader/dshow/cmediasample.c \
+                                        loader/dshow/graph.c \
                                         loader/dshow/guids.c \
                                         loader/dshow/inputpin.c \
                                         loader/dshow/mediatype.c \

-- 
Homepage: http://www.sesse.net/



More information about the MPlayer-dev-eng mailing list