Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Commit

Permalink
Digital TV: new Digital TV options, split from analog capture options
Browse files Browse the repository at this point in the history
1. General
- Split menu entry into: Open Digital TV / Open Analog Capture. File->Open Device now only refers to analog device
- Split class OpenDeviceData into OpenDeviceAnalogData and OpenDeviceDigitalData
- Channel navigation panel: only enabled tabs visible (depending on Digital TV options). Set initial active tab depending
on current channel type.
- Add IGMP membership management: manage IGMP group join/leave for multicast IPTV streaming sources.
Supports only IPv4 and IGMPv2. IPv6 and IGMPv3 could be added in the future if needed.
- Add shortcut for Digital TV

2. Exception handling:
- error controls (checking devices, etc.) moved from the general entry point to each channel switch operation
- Change current behavior: when error switching to a channel -> show error message in info bar and then stay ready for switching to another channel
- If the IPTV switching channel operation fails, we don't change the window size

3. Options & preferences:
- Split Digital TV options from analog capture
- New Digital TV options: DVB (BDA) and IPTV (include option: enable/disable IGMP multicast membership management)
  • Loading branch information
xpc1000 committed Oct 30, 2014
1 parent b288546 commit 97d8f42
Show file tree
Hide file tree
Showing 28 changed files with 1,174 additions and 443 deletions.
19 changes: 14 additions & 5 deletions src/mpc-hc/AppSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@ CAppSettings::CAppSettings()
, nAudioMaxNormFactor(400)
, bAllowOverridingExternalSplitterChoice(false)
, iAnalogCountry(1)
, iDefaultCaptureDevice(0)
, bEnabledAnalogCapture(false)
, bEnabledDVB(false)
, bEnabledIPTV(false)
, bUseIGMPMembership(false)
, fExitFullScreenAtTheEnd(true)
, fLaunchfullscreen(false)
, fD3DFullscreen(false)
Expand Down Expand Up @@ -803,14 +806,15 @@ void CAppSettings::SaveSettings()
pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, fLCDSupport);

// Save analog capture settings
pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, iDefaultCaptureDevice);
pApp->WriteProfileInt(IDS_R_CAPTURE, IDS_RS_ENABLE_ANALOGCAPTURE, bEnabledAnalogCapture);
pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, strAnalogVideo);
pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, strAnalogAudio);
pApp->WriteProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, iAnalogCountry);

// Save digital capture settings (BDA)
pApp->WriteProfileString(IDS_R_DVB, nullptr, nullptr); // Ensure the section is cleared before saving the new settings

pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_ENABLE_DVB, bEnabledDVB);
pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER, strBDANetworkProvider);
pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER, strBDATuner);
pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER, strBDAReceiver);
Expand All @@ -824,6 +828,8 @@ void CAppSettings::SaveSettings()
pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, nDVBLastChannel);
pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, nDVBRebuildFilterGraph);
pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, nDVBStopFilterGraph);
pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_ENABLE_IPTV, bEnabledIPTV);
pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_USE_IGMPMEMBERSHIP, bUseIGMPMembership);

for (size_t i = 0; i < m_DVBChannels.size(); i++) {
CString numChannel;
Expand Down Expand Up @@ -1593,16 +1599,17 @@ void CAppSettings::LoadSettings()

fLCDSupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, FALSE);

// Save analog capture settings
iDefaultCaptureDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, 0);
// Load analog capture settings
bEnabledAnalogCapture = !!pApp->GetProfileInt(IDS_R_CAPTURE, IDS_RS_ENABLE_ANALOGCAPTURE, FALSE);
strAnalogVideo = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, _T("dummy"));
strAnalogAudio = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, _T("dummy"));
iAnalogCountry = pApp->GetProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, 1);

// Load digital TV settings
bEnabledDVB = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_ENABLE_DVB, FALSE);
strBDANetworkProvider = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER);
strBDATuner = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER);
strBDAReceiver = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER);
//sBDAStandard = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD);
iBDAScanFreqStart = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, 474000);
iBDAScanFreqEnd = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, 858000);
iBDABandwidth = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, 8);
Expand All @@ -1614,6 +1621,8 @@ void CAppSettings::LoadSettings()
nDVBStopFilterGraph = (DVB_StopFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, DVB_STOP_FG_WHEN_SWITCHING);

nNextChannelCount = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_NEXTCHANNELCOUNT, 0);
bEnabledIPTV = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_ENABLE_IPTV, FALSE);
bUseIGMPMembership = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_USE_IGMPMEMBERSHIP, FALSE);
for (int iChannel = 0; ; iChannel++) {
CString strTemp;
strTemp.Format(_T("%d"), iChannel);
Expand Down
9 changes: 7 additions & 2 deletions src/mpc-hc/AppSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,11 +532,14 @@ class CAppSettings

// Sync Renderer Settings

// Capture (BDA configuration)
int iDefaultCaptureDevice; // Default capture device (analog=0, 1=digital)
// Capture (Analog configuration)
bool bEnabledAnalogCapture;
CString strAnalogVideo;
CString strAnalogAudio;
int iAnalogCountry;

// Digital TV configuration
bool bEnabledDVB;
CString strBDANetworkProvider;
CString strBDATuner;
CString strBDAReceiver;
Expand All @@ -551,6 +554,8 @@ class CAppSettings
UINT nNextChannelCount;
DVB_RebuildFilterGraph nDVBRebuildFilterGraph;
DVB_StopFilterGraph nDVBStopFilterGraph;
bool bEnabledIPTV;
bool bUseIGMPMembership;

// Internal Filters
bool SrcFilters[SRC_LAST + !SRC_LAST];
Expand Down
209 changes: 209 additions & 0 deletions src/mpc-hc/IPTVMcastTools.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* (C) 2009-2014 see Authors.txt
*
* This file is part of MPC-HC.
*
* MPC-HC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* MPC-HC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "stdafx.h"
#include <afxmt.h>
#include "IPTVMcastTools.h"
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <mswsock.h>

#define _BSD_SOURCE

typedef int socklen_t;

#define UDP_TX_BUF_SIZE 32768
#define UDP_MAX_PKT_SIZE 65536



CIPTVMcastTools::CIPTVMcastTools()
: m_udp_fd(0),
m_socket(0),
m_is_multicast(false)

{
}

CIPTVMcastTools::~CIPTVMcastTools()
{
}


SOCKET CIPTVMcastTools::udp_socket_create(UINT32 local_addr, USHORT port)
{
int iRet = -1;
SOCKET udp_fd = -1;

// Initialize Winsock
if (WSAStartup(MAKEWORD(2, 2), &m_wsa) == 0) {
// Create socket
udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_fd != INVALID_SOCKET) {

memset(&m_sockaddr, 0, sizeof(m_sockaddr));
m_sockaddr.sin_family = AF_INET;
m_sockaddr.sin_port = port;
m_sockaddr.sin_addr.s_addr = local_addr;

int reuse = 1;
iRet = setsockopt(udp_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));

if (iRet != SOCKET_ERROR) {
// bind the socket
iRet = bind(udp_fd, (SOCKADDR*)&m_sockaddr, sizeof(m_sockaddr));
if (iRet != SOCKET_ERROR) {
iRet = udp_fd;
} else {
HRESULT hr = WSAGetLastError();
TRACE(_T("Error when binding socket: %u \n"), hr);
}
}
}
}

if (iRet < 0) {
// Something went wrong
if (udp_fd >= 0) {
closesocket(udp_fd);
ASSERT(FALSE);
}
WSACleanup();
}
return iRet;
}

void CIPTVMcastTools::udp_socket_close()
{
closesocket(m_udp_fd);
WSACleanup();
m_udp_fd = 0;
m_socket = 0;
m_is_multicast = false;
}


CString CIPTVMcastTools::get_IPv4_Addr(CString sAddr)
{
CString sIPAddr = _T("0.0.0.0");

int iPos0 = sAddr.Find(_T("@"));
int iBase = 1;
if (iPos0 < 0) {
iPos0 = sAddr.Find(_T("://"));
iBase = 3;
}
if (iPos0 >= 0) {
int iPos1 = sAddr.ReverseFind(_T(':'));
if (iPos1 < 0) {
iPos1 = sAddr.GetLength() - 1;
}
sIPAddr = sAddr.Mid(iBase + iPos0, iPos1 - iPos0 - iBase);
} else {
ASSERT(FALSE);
}
return sIPAddr;
}

USHORT CIPTVMcastTools::get_IPv4_Port(CString sAddr)
{
USHORT uPort;
int iPos = sAddr.ReverseFind(_T(':'));
CString sPort = sAddr.Right(sAddr.GetLength() - iPos - 1);
CT2CA pszConvertedAnsiString(sPort);
char* str = pszConvertedAnsiString;
uPort = atoi(str);

return uPort;
}

bool CIPTVMcastTools::is_multicast_address(UINT32 uIPAddr)
{
return ((uIPAddr >= MULTICAST_FROM) && (uIPAddr <= MULTICAST_TO));
}


int CIPTVMcastTools::udp_multicast_join_group(UINT32 ip_addr, USHORT port)
{
int iResult = 0;

// checks whether the address is within the range of addresses reserved for multicasting
m_is_multicast = is_multicast_address(ip_addr);

if (m_is_multicast) {
m_imr.imr_interface.s_addr = htonl(INADDR_ANY);
m_imr.imr_multiaddr.s_addr = ip_addr;

m_udp_fd = udp_socket_create(htonl(INADDR_ANY), port);
if (m_udp_fd <= 0) {
iResult = m_udp_fd;
} else {
iResult = join_source_group(m_udp_fd, m_imr.imr_multiaddr.s_addr, m_imr.imr_interface.s_addr);

if (iResult != 0) {
HRESULT hr = WSAGetLastError();
TRACE(_T("Error when trying to join multicast group: %u \n"), hr);
WSACleanup();
ASSERT(FALSE);
}
}
}

return iResult;
}

int CIPTVMcastTools::udp_multicast_join_group(CString sAddr)
{
int iResult;
CT2CA pszConvertedAnsiString(get_IPv4_Addr(sAddr));
char* sGrpAddr = pszConvertedAnsiString;

USHORT uPort = get_IPv4_Port(sAddr);
iResult = udp_multicast_join_group(inet_addr(sGrpAddr), uPort);

return iResult;
}

void CIPTVMcastTools::udp_multicast_leave_group()
{
if (m_is_multicast && m_udp_fd > 0) {
leave_source_group(m_udp_fd, m_imr.imr_multiaddr.s_addr, m_imr.imr_interface.s_addr);
udp_socket_close();
}
}

int CIPTVMcastTools::join_source_group(int sd, UINT32 grpaddr, UINT32 iaddr)
{
struct ip_mreq imr;

imr.imr_multiaddr.s_addr = grpaddr;
imr.imr_interface.s_addr = iaddr;
return setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&imr, sizeof(imr));
}


int CIPTVMcastTools::leave_source_group(int sd, UINT32 grpaddr, UINT32 iaddr)
{
struct ip_mreq_source imr;

imr.imr_multiaddr.s_addr = grpaddr;
imr.imr_interface.s_addr = iaddr;
return setsockopt(sd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&imr, sizeof(imr));
}
59 changes: 59 additions & 0 deletions src/mpc-hc/IPTVMcastTools.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* (C) 2003-2006 Gabest
* (C) 2006-2014 see Authors.txt
*
* This file is part of MPC-HC.
*
* MPC-HC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* MPC-HC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#pragma once

// Multicast range:
#define MULTICAST_FROM inet_addr("224.0.0.0")
#define MULTICAST_TO inet_addr("239.255.255.255")

class CIPTVMcastTools
{
public:
CIPTVMcastTools();
~CIPTVMcastTools();

// Membership management
int udp_multicast_join_group(CString sAddr);
int udp_multicast_join_group(UINT32 ip_addr, USHORT port);
void udp_multicast_leave_group();

private:
SOCKET m_udp_fd;
boolean m_is_multicast;
SOCKET m_socket;
struct sockaddr_in m_sockaddr;
WSADATA m_wsa;
struct ip_mreq m_imr;

// Socket management
SOCKET udp_socket_create(UINT32 local_addr, USHORT port);
void udp_socket_close();

// Membership management
int join_source_group(int sd, UINT32 grpaddr, UINT32 iaddr);
int leave_source_group(int sd, UINT32 grpaddr, UINT32 iaddr);
CString get_IPv4_Addr(CString sAddr);
USHORT get_IPv4_Port(CString sAddr);
bool is_multicast_address(UINT32 uIPAddr);

};

0 comments on commit 97d8f42

Please sign in to comment.