Hi All!
Finally I’ve managed adding IPTV support to the MediaPortal. It’s based on a “fake” IPTV tuner card, which receives RTSP/UDP/TCP unicast/multicast MPEG-2 traffic and feeds it to the rest MediaPortal directshow filters. Patch was checked on Windows Vista Home Premium and Windows XP MCE 2005.
Here comes the howto.
1. Download and install CyberLink PowerDVD (trial) from http://www.cyberlink.com. Actually, we need only “CyberLink MPEG Muxer” direct show filter, therefore any software, containing this filter will do.
2. Download and install http://www.elecard.com/products/products-pc/consumer/mpeg2-decoder-plugin/. It has trial period and costs only $17.50 (thanks to Christmas discount).
3. Check if Windows Media Player can play any of you IPTV channel (menu File – Open URL - elecard://225.1.1.1:1234/udp). Replace 225.1.1.1:1234 with IPORT of your IPTV channel. GraphEdit could help too (menu File - Render URL, elecard://225.1.1.1:1234/udp, menu Graph - Play).
4. Install MediaPortal 0.2.3.0. Overwrite files in MediaPortal installation folder with the files from the supplied archive MP-0.2.3.0-iptv.zip (mind the directories in the archive).
5. Insert the fragment:
<capturecard commercialname="IPTV BuiltIn Card" capturename="IPTV BuiltIn" devid="IPTV BuiltIn">
<capabilities tv="true" radio="false" mpeg2="true" mce="false" sw="false" bda="false"/>
<tv>
<interface cat="capture" video="" audio="" mpeg2="0"/>
<filters>
<filter cat="tvtuner" name="Elecard NWSource-Plus" checkdevice="false"/>
<filter cat="demuxer" name="MainConcept MPEG Push Demultiplexer" checkdevice="false"/>
<filter cat="capture" name="CyberLink MPEG Muxer" checkdevice="false"/>
</filters>
<connections>
</connections>
</tv>
</capturecard>
to the file CaptureCardDefinitions.xml before </capturecards> at the very end.
6. Run MediaPortal Configuration, go to Television – Capture Cards – Add – (it should find IPTV Builtin Card) – Autotune – Add. Enter the channel name into the first edit box. The channel name must consist of channel description followed by space and the URL. For example: BBC World elecard://225.1.1.1:1234/udp
7. Disable a firewall.
8. Run MediaPortal.
Good luck!
p.s. For those, who wants to compile new exe and dlls themselves here is the diff:
***** SinkGraph.cs
71: protected string _videoCaptureFilterMoniker = "";
72: protected FilterGraph _filterGrph = null;
73: protected DirectShowLib.IFileSourceFilter _tvFileSourceInterface = null;
74: protected IBaseFilter _filterDemuxer = null;
75: protected IBaseFilter _tvTuner = null;
76: protected IGraphBuilder _graphBuilderInterface = null;
***** SINKGRAPH.CS.BAK
71: protected string _videoCaptureFilterMoniker = "";
72: protected IGraphBuilder _graphBuilderInterface = null;
*****
***** SinkGraph.cs
494: {
495: if (!channel.Name.Contains(@"://"))
496: _tvAudioTunerInterface.put_TVAudioMode(TVAudioMode.Mono | TVAudioMode.LangA);
497: if ( _graphState != State.TimeShifting && _graphState != State.Viewing )
***** SINKGRAPH.CS.BAK
490: {
491: _tvAudioTunerInterface.put_TVAudioMode(TVAudioMode.Mono | TVAudioMode.LangA);
492: if ( _graphState != State.TimeShifting && _graphState != State.Viewing )
*****
***** SinkGraph.cs
523:
524: if (channel.Name.Contains(@"://"))
525: {
526: IMediaControl mediaCtrl = null;
527: int hr;
528:
529: if (_mpeg2DemuxHelper.IsRendered)
530: {
531: mediaCtrl = (IMediaControl)_filterGrph;
532: hr = mediaCtrl.Stop();
533: DsError.ThrowExceptionForHR(hr);
534: }
535:
536: string streamUrl = channel.Name;
537: streamUrl = streamUrl.Remove(0, streamUrl.LastIndexOf(" ") + 1);
538: hr = _tvFileSourceInterface.Load(streamUrl, null);
539: DsError.ThrowExceptionForHR(hr);
540:
541: IPin oPin;
542: hr = _captureGraphBuilderInterface.FindPin(_tvTuner, PinDirection.Output, null, MediaType.Stream, false, 0, out oPin);
544: if (hr == 0) oPin.Disconnect();
545:
546: hr = _captureGraphBuilderInterface.RenderStream(null, MediaType.Stream, _tvTuner, null, _filterDemuxer);
547: DsError.ThrowExceptionForHR(hr);
548:
549: for (int i = 0; i < 40; i++)
550: {
551: System.Threading.Thread.Sleep(100);
552: int hr2 = _captureGraphBuilderInterface.FindPin(_filterDemuxer, PinDirection.Output, null, MediaType.Video, false, 0, out oPin);
554: if (hr2 == 0) oPin.Disconnect();
555: int hr3 = _captureGraphBuilderInterface.FindPin(_filterDemuxer, PinDirection.Output, null, MediaType.Audio, false, 0, out oPin);
557: if (hr3 == 0) oPin.Disconnect();
558: if ((hr2 == 0) && (hr3 == 0)) break;
559: }
560:
561: hr = _captureGraphBuilderInterface.RenderStream(null, MediaType.Video, _filterDemuxer, null, _filterCapture);
562: DsError.ThrowExceptionForHR(hr);
563: hr = _captureGraphBuilderInterface.RenderStream(null, MediaType.Audio, _filterDemuxer, null, _filterCapture);
564: DsError.ThrowExceptionForHR(hr);
565:
566: if (mediaCtrl != null)
567: mediaCtrl.Run();
568: Log.Info("SinkGraph:TuneChannel() loaded new url: {0}", streamUrl);
569: }
570:
571: if ( _channelNumber < (int)ExternalInputs.svhs )
***** SINKGRAPH.CS.BAK
518:
519: if ( _channelNumber < (int)ExternalInputs.svhs )
*****
***** SinkGraph.cs
1008: {
1009: if (_filterDemuxer != null)
1010: return true;
1011: if ( _tvTunerInterface == null )
***** SINKGRAPH.CS.BAK
956: {
957: if ( _tvTunerInterface == null )
*****
***** SinkGraph.cs
1021: {
1022: if (_filterDemuxer != null)
1023: return 100;
1024: if (_tvTunerInterface == null)
1025: return 1;
***** SINKGRAPH.CS.BAK
967: {
968: if ( _tvTunerInterface == null )
969: return 1;
*****
***** SinkGraph.cs
1036: {
1037: if (_filterDemuxer != null)
1038: return 100;
1039: if (_tvTunerInterface == null)
1040: return 1;
***** SINKGRAPH.CS.BAK
980: {
981: if ( _tvTunerInterface == null )
982: return 1;
*****
***** SinkGraphEx.cs
142: Log.Info("SinkGraphEx: Create new filter graph (IGraphBuilder)");
143: _filterGrph = new FilterGraph();
144: _graphBuilderInterface = (IGraphBuilder)_filterGrph;
145:
***** SINKGRAPHEX.CS.BAK
142: Log.Info("SinkGraphEx: Create new filter graph (IGraphBuilder)");
143: _graphBuilderInterface = (IGraphBuilder)new FilterGraph();
144:
*****
***** SinkGraphEx.cs
193: // through which the filters are accessable. More implementation independent...
194: if (dsFilter.Category == "tvtuner")
195: {
196: _tvTuner = dsFilter.DSFilter;
197: _tvTunerInterface = dsFilter.DSFilter as IAMTVTuner;
198: _tvFileSourceInterface = dsFilter.DSFilter as IFileSourceFilter;
199: }
200: if (dsFilter.Category == "tvaudio") _tvAudioTunerInterface = dsFilter.DSFilter as IAMTVAudio;
201: if (dsFilter.Category == "demuxer") _filterDemuxer = dsFilter.DSFilter;
202: if (dsFilter.Category == "capture") _filterCapture = dsFilter.DSFilter;
***** SINKGRAPHEX.CS.BAK
192: // through which the filters are accessable. More implementation independent...
193: if (dsFilter.Category == "tvtuner") _tvTunerInterface = dsFilter.DSFilter as IAMTVTuner;
194: if (dsFilter.Category == "tvaudio") _tvAudioTunerInterface = dsFilter.DSFilter as IAMTVAudio;
195: if (dsFilter.Category == "capture") _filterCapture = dsFilter.DSFilter;
*****
***** EditCaptureCardForm.cs
245:
246: availableVideoDevices.Add("IPTV BuiltIn");
247: availableVideoDeviceMonikers.Add("IPTV BuiltIn");
248:
249: FilterHelper.GetMPEG2VideoEncoders(availableVideoCompressors);
***** EDITCAPTURECARDFORM.CS.BAK
245:
246: FilterHelper.GetMPEG2VideoEncoders(availableVideoCompressors);
*****
Finally I’ve managed adding IPTV support to the MediaPortal. It’s based on a “fake” IPTV tuner card, which receives RTSP/UDP/TCP unicast/multicast MPEG-2 traffic and feeds it to the rest MediaPortal directshow filters. Patch was checked on Windows Vista Home Premium and Windows XP MCE 2005.
Here comes the howto.
1. Download and install CyberLink PowerDVD (trial) from http://www.cyberlink.com. Actually, we need only “CyberLink MPEG Muxer” direct show filter, therefore any software, containing this filter will do.
2. Download and install http://www.elecard.com/products/products-pc/consumer/mpeg2-decoder-plugin/. It has trial period and costs only $17.50 (thanks to Christmas discount).
3. Check if Windows Media Player can play any of you IPTV channel (menu File – Open URL - elecard://225.1.1.1:1234/udp). Replace 225.1.1.1:1234 with IPORT of your IPTV channel. GraphEdit could help too (menu File - Render URL, elecard://225.1.1.1:1234/udp, menu Graph - Play).
4. Install MediaPortal 0.2.3.0. Overwrite files in MediaPortal installation folder with the files from the supplied archive MP-0.2.3.0-iptv.zip (mind the directories in the archive).
5. Insert the fragment:
<capturecard commercialname="IPTV BuiltIn Card" capturename="IPTV BuiltIn" devid="IPTV BuiltIn">
<capabilities tv="true" radio="false" mpeg2="true" mce="false" sw="false" bda="false"/>
<tv>
<interface cat="capture" video="" audio="" mpeg2="0"/>
<filters>
<filter cat="tvtuner" name="Elecard NWSource-Plus" checkdevice="false"/>
<filter cat="demuxer" name="MainConcept MPEG Push Demultiplexer" checkdevice="false"/>
<filter cat="capture" name="CyberLink MPEG Muxer" checkdevice="false"/>
</filters>
<connections>
</connections>
</tv>
</capturecard>
to the file CaptureCardDefinitions.xml before </capturecards> at the very end.
6. Run MediaPortal Configuration, go to Television – Capture Cards – Add – (it should find IPTV Builtin Card) – Autotune – Add. Enter the channel name into the first edit box. The channel name must consist of channel description followed by space and the URL. For example: BBC World elecard://225.1.1.1:1234/udp
7. Disable a firewall.
8. Run MediaPortal.
Good luck!
p.s. For those, who wants to compile new exe and dlls themselves here is the diff:
***** SinkGraph.cs
71: protected string _videoCaptureFilterMoniker = "";
72: protected FilterGraph _filterGrph = null;
73: protected DirectShowLib.IFileSourceFilter _tvFileSourceInterface = null;
74: protected IBaseFilter _filterDemuxer = null;
75: protected IBaseFilter _tvTuner = null;
76: protected IGraphBuilder _graphBuilderInterface = null;
***** SINKGRAPH.CS.BAK
71: protected string _videoCaptureFilterMoniker = "";
72: protected IGraphBuilder _graphBuilderInterface = null;
*****
***** SinkGraph.cs
494: {
495: if (!channel.Name.Contains(@"://"))
496: _tvAudioTunerInterface.put_TVAudioMode(TVAudioMode.Mono | TVAudioMode.LangA);
497: if ( _graphState != State.TimeShifting && _graphState != State.Viewing )
***** SINKGRAPH.CS.BAK
490: {
491: _tvAudioTunerInterface.put_TVAudioMode(TVAudioMode.Mono | TVAudioMode.LangA);
492: if ( _graphState != State.TimeShifting && _graphState != State.Viewing )
*****
***** SinkGraph.cs
523:
524: if (channel.Name.Contains(@"://"))
525: {
526: IMediaControl mediaCtrl = null;
527: int hr;
528:
529: if (_mpeg2DemuxHelper.IsRendered)
530: {
531: mediaCtrl = (IMediaControl)_filterGrph;
532: hr = mediaCtrl.Stop();
533: DsError.ThrowExceptionForHR(hr);
534: }
535:
536: string streamUrl = channel.Name;
537: streamUrl = streamUrl.Remove(0, streamUrl.LastIndexOf(" ") + 1);
538: hr = _tvFileSourceInterface.Load(streamUrl, null);
539: DsError.ThrowExceptionForHR(hr);
540:
541: IPin oPin;
542: hr = _captureGraphBuilderInterface.FindPin(_tvTuner, PinDirection.Output, null, MediaType.Stream, false, 0, out oPin);
544: if (hr == 0) oPin.Disconnect();
545:
546: hr = _captureGraphBuilderInterface.RenderStream(null, MediaType.Stream, _tvTuner, null, _filterDemuxer);
547: DsError.ThrowExceptionForHR(hr);
548:
549: for (int i = 0; i < 40; i++)
550: {
551: System.Threading.Thread.Sleep(100);
552: int hr2 = _captureGraphBuilderInterface.FindPin(_filterDemuxer, PinDirection.Output, null, MediaType.Video, false, 0, out oPin);
554: if (hr2 == 0) oPin.Disconnect();
555: int hr3 = _captureGraphBuilderInterface.FindPin(_filterDemuxer, PinDirection.Output, null, MediaType.Audio, false, 0, out oPin);
557: if (hr3 == 0) oPin.Disconnect();
558: if ((hr2 == 0) && (hr3 == 0)) break;
559: }
560:
561: hr = _captureGraphBuilderInterface.RenderStream(null, MediaType.Video, _filterDemuxer, null, _filterCapture);
562: DsError.ThrowExceptionForHR(hr);
563: hr = _captureGraphBuilderInterface.RenderStream(null, MediaType.Audio, _filterDemuxer, null, _filterCapture);
564: DsError.ThrowExceptionForHR(hr);
565:
566: if (mediaCtrl != null)
567: mediaCtrl.Run();
568: Log.Info("SinkGraph:TuneChannel() loaded new url: {0}", streamUrl);
569: }
570:
571: if ( _channelNumber < (int)ExternalInputs.svhs )
***** SINKGRAPH.CS.BAK
518:
519: if ( _channelNumber < (int)ExternalInputs.svhs )
*****
***** SinkGraph.cs
1008: {
1009: if (_filterDemuxer != null)
1010: return true;
1011: if ( _tvTunerInterface == null )
***** SINKGRAPH.CS.BAK
956: {
957: if ( _tvTunerInterface == null )
*****
***** SinkGraph.cs
1021: {
1022: if (_filterDemuxer != null)
1023: return 100;
1024: if (_tvTunerInterface == null)
1025: return 1;
***** SINKGRAPH.CS.BAK
967: {
968: if ( _tvTunerInterface == null )
969: return 1;
*****
***** SinkGraph.cs
1036: {
1037: if (_filterDemuxer != null)
1038: return 100;
1039: if (_tvTunerInterface == null)
1040: return 1;
***** SINKGRAPH.CS.BAK
980: {
981: if ( _tvTunerInterface == null )
982: return 1;
*****
***** SinkGraphEx.cs
142: Log.Info("SinkGraphEx: Create new filter graph (IGraphBuilder)");
143: _filterGrph = new FilterGraph();
144: _graphBuilderInterface = (IGraphBuilder)_filterGrph;
145:
***** SINKGRAPHEX.CS.BAK
142: Log.Info("SinkGraphEx: Create new filter graph (IGraphBuilder)");
143: _graphBuilderInterface = (IGraphBuilder)new FilterGraph();
144:
*****
***** SinkGraphEx.cs
193: // through which the filters are accessable. More implementation independent...
194: if (dsFilter.Category == "tvtuner")
195: {
196: _tvTuner = dsFilter.DSFilter;
197: _tvTunerInterface = dsFilter.DSFilter as IAMTVTuner;
198: _tvFileSourceInterface = dsFilter.DSFilter as IFileSourceFilter;
199: }
200: if (dsFilter.Category == "tvaudio") _tvAudioTunerInterface = dsFilter.DSFilter as IAMTVAudio;
201: if (dsFilter.Category == "demuxer") _filterDemuxer = dsFilter.DSFilter;
202: if (dsFilter.Category == "capture") _filterCapture = dsFilter.DSFilter;
***** SINKGRAPHEX.CS.BAK
192: // through which the filters are accessable. More implementation independent...
193: if (dsFilter.Category == "tvtuner") _tvTunerInterface = dsFilter.DSFilter as IAMTVTuner;
194: if (dsFilter.Category == "tvaudio") _tvAudioTunerInterface = dsFilter.DSFilter as IAMTVAudio;
195: if (dsFilter.Category == "capture") _filterCapture = dsFilter.DSFilter;
*****
***** EditCaptureCardForm.cs
245:
246: availableVideoDevices.Add("IPTV BuiltIn");
247: availableVideoDeviceMonikers.Add("IPTV BuiltIn");
248:
249: FilterHelper.GetMPEG2VideoEncoders(availableVideoCompressors);
***** EDITCAPTURECARDFORM.CS.BAK
245:
246: FilterHelper.GetMPEG2VideoEncoders(availableVideoCompressors);
*****