oberon_dvbsbridge Posted April 25, 2008 Posted April 25, 2008 (edited) Goodday, I am trying to get transport stream from DVBViewer using plugin SDK. Unfortunately this task is appeared to be more complicated than I originally thought. I have written a very simple plugin in C++, which essentially does the following (nothing): extern "C" char* __stdcall Copyright() { return "Me"; } extern "C" char* __stdcall Version() { return "0.1"; } extern "C" char* __stdcall LibTyp() { return "Plugin"; } extern "C" char* __stdcall PluginName() { return "test plugin"; } TRebuildFunc g_RebuildFunc; HWND g_wnd; extern "C" void __stdcall SetAppHandle(HWND wnd, TRebuildFunc RebuildFunc) { g_RebuildFunc = RebuildFunc; g_wnd = wnd; } extern "C" bool __stdcall Execute(TTuner* PTuner, int** PPluginPids) { return true; } extern "C" void __stdcall PidCallback(TTStream* Stream) { } However when I copy resulting dll into Plugins folder of DVBViewer and start it up I see that DVBViewer stops producing the audio/video signal - e.g. there is no video playing on the screen. In my logging I see that Copyright, Version, LibTyp, PluginName, SetAppHandle and Execute function are being called. PidCallback is not called. If I remove the plugin and start DVBViewer again, then everything is Ok. I have a feeling that this is something very basic, which I do wrong, but I cannot understand what exactly. Can someone help me please? Edited April 25, 2008 by oberon_dvbsbridge Quote
oberon_dvbsbridge Posted April 29, 2008 Author Posted April 29, 2008 It is a pity that knowledgeable people on this board often ignore posts about plugin SDK. I will start answering my own questions myself as I go forward in hope that it will help others. For the fact that streaming did not want to start when my plugin was loaded was caused by incorrect return value of Execute function. Bool in C/Windows most probably does not match directly on Boolean type in Delphi. The problem was solved by returning 0 instead of true. extern "C" bool __stdcall Execute(TTuner* PTuner, int** PPluginPids) { return 0; } The next issue was to install the transport stream callback. If I did inside the Execute function SendMessage(wnd,WM_DVBVIEWER,MSG_STARTFILTER, 0x11); SendMessage(wnd,WM_DVBVIEWER,MSG_STARTFILTER, 0x12); SendMessage(wnd,WM_DVBVIEWER,MSG_STARTFILTER, 0xFFFF); the PidCallback function was never called after the first Execute. The transport stream always started coming from the second channel change (second Execute). I have assumed that synchronous SendMessage could not have been processed correctly inside the Execute handler and substituted SendMessage with PostMessage. And - yes - the problem was solved. So, to set the transport stream filters from Execute handler one must do the following PostMessage(wnd,WM_DVBVIEWER,MSG_STARTFILTER, 0x11); PostMessage(wnd,WM_DVBVIEWER,MSG_STARTFILTER, 0x12); PostMessage(wnd,WM_DVBVIEWER,MSG_STARTFILTER, 0xFFFF); However to remove the previously set filters SendMessage should be used to race conditions. Now comes the next issue, which I still do not have the answer for. If I install the filters for audio, video, PMT, PCR, NIT, SDT and PAT packets and save the contents to a file - extern "C" void __stdcall PidCallback(TTStream* Stream) { fwrite(Stream, sizeof(TTStream), 1, stream_file); } - the resulting file does not play correctly. Upon close inspection of file contents I have noticed that saved transport stream packets sometimes are longer by one or two bytes then 188 bytes e.g. by jumping with 188 bytes through the file, starting from synchrobyte (0x47) I expect that it will land after each jump on 0x47. However it lands from time to time on another value, while 0x47 is the next byte in file. Does anyone have an explanation to this process and suggestion on how to avoid it? Thanks in advance. Quote
Lars_MQ Posted April 30, 2008 Posted April 30, 2008 Sorry, sometimes we have a live outside the DVBViewer, you know Anyway, here is a demo compilation of all usefull callback variations. It's delphi but should be pretty simple to translate to C. Except the RAW callbacks, it's what I use in the netstreaming plugin. Remember the Transponder callback may return the full transponder but some cards with hardwarefilters (SS2 &Co) only return the PIDs, the DVBViewer (or you) set. unit uMain; interface uses Windows; function Copyright: PChar; stdcall; function EventMsg(EventType: Integer; Data: Pointer): Integer; stdcall; function LibTyp: PChar; stdcall; function PluginName: PChar; stdcall; procedure SetAppHandle(Handle: THandle; RebuildFunc: pointer); stdcall; function Version: Pchar; stdcall; implementation type TMSG_PIDCallback = packed record Pid: Word; Callback: Pointer; Priority: Boolean; end; PMSG_PIDCallback = ^TMSG_PIDCallback; TTransCallData = record TransCall: Pointer; Param: DWord; end; PTransCallData = ^TTransCallData; TTStream = record header: array[0..3] of byte; data: array[0..183] of byte; end; PTStream = ^TTStream; TTunerType = (ttCable, ttSatellite, ttTerrestrial, ttATSC, ttIPTV); TChannelGroup = (cgA, cgB, cgC); TTunerLanguage = array[0..2] of Char; PTuner = ^TTuner; TTuner = record TunerType: TTunerType; //It's a byte Group: TChannelGroup; //It's a byte Unused1: Byte; Flags: Byte; Frequency: DWord; SymbolRate: DWord; LOF: Word; PMT: Word; Volume: Byte; Unused: Byte; SatModulation: Byte; AVFormat: Byte; FEC: Byte; Audiochannel: Byte; Unused3: Word; Polarity: Byte; Unused4: Byte; Unused5: Word; Tone: Byte; EPGFlag: Byte; DiSEqCValue: Word; DiSEqC: Byte; Language: TTunerLanguage; // 3 bytes AudioPID: Word; NetworkNr: Byte; Favourite: Byte; VideoPID: Word; TransportStreamID: Word; TelePID: Word; NetworkID: Word; SID: Word; PCRPID: Word; end; const WM_DVBVIEWER = $B2C2; MSG_VERSION = $1018; MSG_ADDTSCALL = $2210; MSG_DELTSCALL = $2211; MSG_ADDRAWTSCALL = $2214; MSG_DELRAWTSCALL = $2215; MSG_STARTPIDCALLBACK = $45104; MSG_STOPPIDCALLBACK = $45105; evUnload = 0; evInitComplete = 3; evTuneChannel = 999; evRemoveChannel = 998; var DVBViewerHandle: THandle; NewCallback: Boolean = false; CurrentTuner: TTuner; function Version: Pchar; stdcall; begin result := '1.0.0'; end; function Copyright: PChar; stdcall; begin result := 'written by Lars'; end; function LibTyp: PChar; stdcall; begin result := 'Plugin'; end; procedure Terminate; begin //Do your stuff end; procedure Init; begin //Do your stuff end; function PluginName: PChar; stdcall; begin result := 'Demo callback'; end; procedure SetAppHandle(Handle: THandle; RebuildFunc: pointer); stdcall; var version: Integer; begin DVBViewerHandle := Handle; version := SendMessage(DVBViewerHandle, WM_DVBVIEWER, MSG_VERSION, 0); NewCallback := version > $0306; end; function IRQ_Transponder_Callback(Buffer: PChar; Size: DWord): Boolean; stdcall; begin result := True; //Do your thing. end; function IRQ_Stream_Callback(Stream: PTStream): Boolean; stdcall; begin result := True; //Do your thing. You get each time one TS Packet (188byte) of the PIDs you set. It is aligned and checked. end; procedure AddTranscall; var c: TTransCallData; begin //Gets all Packets received by the Hardware, no PID filtering (except Cards with hardwarefilters) is done. //This callback gets always one TS-Packet (188 byte), they are guarantied to be aligned and checked. if not NewCallback then exit; c.TransCall := @IRQ_Transponder_Callback; SendMessage(DVBViewerHandle, WM_DVBVIEWER, MSG_ADDTSCALL, DWord(@C)); end; procedure CloseTranscall; var c: TTransCallData; begin //Remember always clean up! if not NewCallback then exit; c.TransCall := @IRQ_Transponder_Callback; SendMessage(DVBViewerHandle, WM_DVBVIEWER, MSG_DELTSCALL, DWord(@C)); end; procedure AddFilter(Pid: Word); var PC: TMSG_PIDCallback; begin PC.Pid := Pid; PC.Callback := @IRQ_Stream_Callback; PC.Priority := false; if NewCallback then SendMessage(DVBViewerHandle, WM_DVBVIEWER, MSG_STARTPIDCALLBACK, DWord(@PC)); end; procedure CloseFilter(Pid: Word); var PC: TMSG_PIDCallback; begin // A PID = $1FFF does mean close all PIDs used. PC.Pid := Pid; PC.Callback := @IRQ_Stream_Callback; if NewCallback then SendMessage(DVBViewerHandle, WM_DVBVIEWER, MSG_STOPPIDCALLBACK, DWord(@PC)); end; function EventMsg(EventType: Integer; Data: Pointer): Integer; stdcall; begin result := 0; case EventType of evUnload: Terminate; evInitComplete: init; evRemoveChannel: begin CloseFilter($1FFF); //for Demo purposes both types of callback. CloseTranscall; end; evTuneChannel: if data<>nil then begin Move(data^, CurrentTuner, sizeof(TTuner)); CloseTranscall; addtranscall; AddFilter(CurrentTuner.PMT); //and so on. end else begin //no tuner close everything. CloseFilter($1FFF); //for Demo purposes both types of callback. CloseTranscall; end; end; end; procedure AddRawTranscall; var c: TTransCallData; begin //This callback gets varying sizes data chunks. //It is the raw data delivered by the Hardware before any processing by the DVBViewer. if not NewCallback then exit; c.TransCall := @IRQ_Transponder_Callback; SendMessage(DVBViewerHandle, WM_DVBVIEWER, MSG_ADDRAWTSCALL, DWord(@C)); end; procedure CloseRawTranscall; var c: TTransCallData; begin //Remember always clean up! if not NewCallback then exit; c.TransCall := @IRQ_Transponder_Callback; SendMessage(DVBViewerHandle, WM_DVBVIEWER, MSG_DELRAWTSCALL, DWord(@C)); end; end. 1 Quote
oberon_dvbsbridge Posted May 7, 2008 Author Posted May 7, 2008 Wow, that's impressive code sample. Big thanks. It makes a lot of things clear. Just a quick additional question - if hardware has a built-in CI module will the audio and video packets, which I receive on PID and transponder callbacks be encrypted or decrypted? [removed] Thanks a lot. Quote
Lars_MQ Posted May 7, 2008 Posted May 7, 2008 The CI/CAM of a dvb-card does its work before the stream is send to the DVBViewer, this is done in hardware and is completly transparent for a dvb-app. Quote
oberon_dvbsbridge Posted June 16, 2008 Author Posted June 16, 2008 Goodday again I have made quite some progress so far thanks to the useful tips and source code, kindly posted in this thread. Now I have a small question, which is hopefully easy to answer for guru's of this site Is there a way to start DVBViewer without audio/video rendering and keep it that way until program shuts down? Or, alternatively, is there a way to put DVBViewer programmatically (via COM or plugin API) in such mode? I also need that this "silent" mode stays after channel changes. Thanks a lot in advance. Quote
Lars_MQ Posted June 16, 2008 Posted June 16, 2008 start with -c and a. choose disable av on minimize and minimize the viewer or b. take a look at the actions.ini. Each entry can be send via postmessage(windowhandle,WM_dvbviewer, MSG_REMOTE, ActionID +100); c. send it via COM Interface sendcommand. Quote
oberon_dvbsbridge Posted June 23, 2008 Author Posted June 23, 2008 Hello. It's me again I have spent almost a day yesterday trying to make channel changes working via Rebuild function (up until now I used the COM functions, but would like to see whether pure plugin API is sufficient to minimize the dependency). Unfortunately not too much progress so far. Hence the question. Is the Rebuild function still in use - can it be used to request the channel change? I use the following C prototype: typedef void (__stdcall* TRebuildFunc)(TTuner* ptuner); Is it correct? My problem is that when I call this function than it only changes the channel in 1 case out of 10. And usually it does not do anything - e.g. no channel change. Are there mandatory parameters of TTuner structure, which must be set when requesting channel change? Because I assume that things like TunerType and Frequency are really needed to identify the channel while Favourite is actually optional. (To clarify - the TTuner structure, which I am using is from the example above and it is correct as the data, which I receive in Execute callback matches actual channel parameters) Thanks in advance. Quote
Lars_MQ Posted June 23, 2008 Posted June 23, 2008 This function is depreciated and does not work. Quote
oberon_dvbsbridge Posted June 23, 2008 Author Posted June 23, 2008 It's a pity. Is there any other way to request a channel change to a particular channel without having to use COM interface? Or let me rephrase Is there any way to request a channel change in GE/TT/... versions of DVBViewer? Quote
Lars_MQ Posted June 23, 2008 Posted June 23, 2008 Via sendmessage (see above) wparam MSG_SETCHANNEL = 0x2204; lparam PSetChannel (a pointer). TSetChannel = packed record Channel: Integer; //Channelnr. use this. ChannelName: PChar; // channelname try not to use end; PSetChannel = ^TSetChannel; This should work. Use the channelNr of this struct and keep the name nil. The caller is responsible for the memory handling so sendmessage is the way to go. Quote
oberon_dvbsbridge Posted June 23, 2008 Author Posted June 23, 2008 Thanks. I really love the support that you guys deliver for your product. It is way better then I used to have up until now with other satellite TV programs. For the channel change - is my assumption correct that channel number is the consequential number of channel description structure in the channels.dat file? E.g. first structure in the file is for channel 0, second one - for channel 1 etc.? Quote
Lars_MQ Posted June 23, 2008 Posted June 23, 2008 No, now that you ask. It's the numering as seen in the channellist. Only the main channels are numbered and the audiosubchannel (which are stored also as channels in the channels.dat for compatibily reasons) have the same channel number as the main channel. Hmm now it gets ugly. Maybe you should take the channelname, but this only gives you the first found channel... Maybe another aproach: wparam MSG_SETSID = 0x2100; lparam PSetServiceID (a pointer) TSetServiceID = packed record ServiceID: Integer; Transponder: Integer; DiSEqC: Byte; end; PSetServiceID = ^TSetServiceID; Same rules as above. Transponder = frequency of the ttuner structure. set diseqc to 255. then it searches for the frequency/ServiceID part. Quote
oberon_dvbsbridge Posted June 23, 2008 Author Posted June 23, 2008 Under this approach (using MSG_SETSID) how the DVBViewer will set the audio PID? Because, for example, the three different channels in DVBViewer - ZDF (2ch), ZDF (AC3) and ZDF (deu) will get the same Freq/SID combination. Quote
Lars_MQ Posted June 23, 2008 Posted June 23, 2008 It will set the first found (the mainchannel). Quote
oberon_dvbsbridge Posted June 23, 2008 Author Posted June 23, 2008 If I may ask the additional question. I have just learned that TechnoTrend, TechniSatz, FireDTV, Satelco and other DVBViewer-offsprings do not feature any of the API. Is this true? Or the plugin API is still supported (including the TS-callbacks and channel change request mechanisms)? Quote
CiNcH Posted June 23, 2008 Posted June 23, 2008 (edited) There is the differentiation between Pro Limited Editions (DVBSHOP.TVplayer for TechnoTrend/Satelco, TT-Viewer, FireDTV Viewer, TechniSat Edition) and GE. First group IMHO does not feature any API, neither C/Delphi nor COM (maybe TechniSat Edition is somehow different...). As for GE it should at least feature the C/Delphi API but I do not know how well they are synchronized (Pro and GE API's), also with respect to the TS/PID callbacks. GE could be pretty well suited as a streaming source as its primary focus is stability (but lacks CI support unfortunately). Think Lars or Griga know better about current API situation, compatibility a.s.o. Edited June 23, 2008 by CiNcH Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.