Reputation: 11
I'm converting working Borland C++ Builder code to C# - interesting, but not always easy...
void listCodecs(int Width, int Height)
{
int iSelected = 0;
ICINFO ci;
BITMAPINFOHEADER bih;
AnsiString asDesc;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = Width;
bih.biHeight = Height;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = BI_RGB;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 1024;
bih.biYPelsPerMeter = 1024;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
for (int c = 0, i = 0; ICInfo(ICTYPE_VIDEO, i, &ci); i++)
{
// Query the compressor for information.
HIC hic = ICOpen(ci.fccType, ci.fccHandler, ICMODE_QUERY);
if (hic)
{
if (ICERR_OK == ICCompressQuery( hic, &bih, NULL))
{
ICGetInfo( hic, &ci, sizeof(ICINFO));
asDesc = ci.szDescription;
// ComboBoxCODEC->Items->Add(as);
}
c++;
ICClose(hic);
}
}
}
I tried to convert to this slightly simplified code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ICINFO
{
public int dwSize;
public int fccType;
public int fccHandler;
public int dwFlags;
public int dwVersion;
public int dwVersionICM;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string szName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szDriver;
}
public class FOURCC
{
public static readonly int DIVX = FOURCC.mmioFOURCC('d', 'i', 'v', 'x');
public static readonly int MP42 = FOURCC.mmioFOURCC('M', 'P', '4', '2');
public static readonly int streamtypeVIDEO = mmioFOURCC('v', 'i', 'd', 's');
public static readonly int streamtypeAUDIO = mmioFOURCC('a', 'u', 'd', 's');
public static readonly int streamtypeMIDI = mmioFOURCC('m', 'i', 'd', 's');
public static readonly int streamtypeTEXT = mmioFOURCC('t', 'x', 't', 's');
public static readonly int ICTYPE_VIDEO = mmioFOURCC('v', 'i', 'd', 'c');
public static readonly int ICTYPE_AUDIO = mmioFOURCC('a', 'u', 'd', 'c');
public static readonly int ICM_FRAMERATE = mmioFOURCC('F', 'r', 'm', 'R');
public static readonly int ICM_KEYFRAMERATE = mmioFOURCC('K', 'e', 'y', 'R');
public static Int32 mmioFOURCC(char ch0, char ch1, char ch2, char ch3)
{
return ((Int32)(byte)(ch0) | ((byte)(ch1) << 8) |
((byte)(ch2) << 16) | ((byte)(ch3) << 24));
}
}
int ChangeCODEC()
{
int cntCodec = 0;
ICINFO ci = new ICINFO();
for (int i = 0; ICBase.ICInfo(FOURCC.ICTYPE_VIDEO, i, ci); i++)
{
cntCodec++;
}
return cntCodec;
}
My problem is that ICInfo doesn't return any sane values in ci - but something is working because the loop runs 13 times, which is my number of installed codecs.
Sorry for the confusion. I have reformulated my question slightly - below is the non-working troublemaker code. I was hoping to create a list of vido codec information, but the list has the expected number of items, but the item data is not as I was expecting.
This is the code from a one-button C# 2008 test application.
Thanks a lot for looking into this!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace vfwApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
VideoCodecs myVideoCodecs = new VideoCodecs();
List<VideoCodecs.ExtractedVideoCodecInformation> levci = myVideoCodecs.showThem();
}
}
public class VideoCodecs
{
public static unsafe class ICBase
{
[DllImport("MSVFW32.dll", CharSet = CharSet.Ansi)]
public static extern bool ICInfo(
int fccType,
int fccHandler,
ICINFO lpicinfo
);
[DllImport("MSVFW32.dll"), PreserveSig]
public static extern int ICOpen(int fccType, int fccHandler, ICMODE wMode);
[DllImport("MSVFW32.dll")]
public static extern int ICClose(int hic);
[DllImport("MSVFW32.dll", CharSet = CharSet.Ansi)]
public static extern int ICGetInfo(
int hic,
ICINFO lpicinfo,
int cb
);
}
public class FOURCC
{
public static readonly int ICTYPE_VIDEO = mmioFOURCC('v', 'i', 'd', 'c');
public static readonly int ICTYPE_AUDIO = mmioFOURCC('a', 'u', 'd', 'c');
public static Int32 mmioFOURCC(char ch0, char ch1, char ch2, char ch3)
{
return ((Int32)(byte)(ch0) | ((byte)(ch1) << 8) | ((byte)(ch2) << 16) | ((byte)(ch3) << 24));
}
}
public enum ICMODE
{
ICMODE_COMPRESS = 1,
ICMODE_DECOMPRESS = 2,
ICMODE_FASTDECOMPRESS = 3,
ICMODE_QUERY = 4,
ICMODE_FASTCOMPRESS = 5,
ICMODE_DRAW = 8
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ICINFO
{
public int dwSize;
public int fccType;
public int fccHandler;
public int dwFlags;
public int dwVersion;
public int dwVersionICM;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string szName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szDriver;
}
public struct ExtractedVideoCodecInformation {
public int fccType;
public int fccHandler;
public int dwVersion;
public string name;
public string description;
public string driver;
}
public List<ExtractedVideoCodecInformation> showThem()
{
int cntCodec = 0;
ICINFO ci = new ICINFO();
ExtractedVideoCodecInformation evci = new ExtractedVideoCodecInformation();
List<ExtractedVideoCodecInformation> levci = new List<ExtractedVideoCodecInformation>();
for (int i = 0; ICBase.ICInfo(FOURCC.ICTYPE_VIDEO, i, ci); i++)
{
int hic = ICBase.ICOpen(ci.fccType, ci.fccHandler, ICMODE.ICMODE_QUERY);
if (hic != 0)
{
ICBase.ICGetInfo(hic, ci, 0);
// None of these fields are valid/sane now >>>
evci.fccType = ci.fccType;
evci.fccHandler = ci.fccHandler;
evci.dwVersion = ci.dwVersion;
evci.name = ci.szName;
evci.description = ci.szDescription;
evci.driver = ci.szDriver;
levci.Add(evci);
// <<< None of these fields are valid/sane now
ICBase.ICClose(hic);
}
cntCodec++;
}
return levci;
}
}
}
Upvotes: 1
Views: 6307
Reputation: 1
I finally got it to work (sort of) by making ICINFO a struct and passing it using the ref keyword like so:
public unsafe static extern bool ICInfo(
uint fccType,
uint fccHandler,
ref ICINFO lpicinfo
);
The string fields don't work yet though. I'll post if I figure that out.
Upvotes: 0
Reputation: 11
Try to use this code
public static readonly int ICTYPE_VIDEO = mmioFOURCC('v', 'i', 'd', 'c');
public static readonly int DIVX = mmioFOURCC('d', 'i', 'v', 'x');
(int)ICOpen(ICTYPE_VIDEO, ci.fccHandler, ICMODE.ICMODE_QUERY);
for get video codecs or this
(int)ICOpen(ICTYPE_VIDEO, DIVX, ICMODE.ICMODE_QUERY);
for get specific(DIVX) codec
Upvotes: 1
Reputation: 5836
The line:
ICBase.ICGetInfo(hic, ci, 0);
should be
ICBase.ICGetInfo(hic, ci, Marshal.SizeOf(ci));
Also, since hic is a handle, you should declare it everywhere as IntPtr instead of int.
Upvotes: 1