Ticket #3580: mythtv-commskip-0.20-fixes.patch

File mythtv-commskip-0.20-fixes.patch, 44.4 KB (added by anonymous, 12 years ago)
  • libs/libmythtv/programinfo.h

     
    1212using namespace std;
    1313typedef QMap<long long, long long> frm_pos_map_t;
    1414typedef QMap<long long, int> frm_dir_map_t;
     15typedef QMap<long long, time_t> pos_time_map_t;
    1516
    1617#define NUMPROGRAMLINES 42
    1718
     
    223224    void SetPositionMap(frm_pos_map_t &, int type,
    224225                        long long min_frm = -1, long long max_frm = -1) const;
    225226    void SetPositionMapDelta(frm_pos_map_t &, int type) const;
     227    int  GetTrackMap( const QString &sChanId, const QString &sStartTime, pos_time_map_t &TrackMap);
    226228
    227229
    228230    // GUI stuff
     
    375377#endif
    376378
    377379/* vim: set expandtab tabstop=4 shiftwidth=4: */
     380
  • libs/libmythtv/programinfo.cpp

     
    25442544    }
    25452545}
    25462546
     2547/////////////////////////////////////////////////////////////////////////////
     2548//                 
     2549// GetTrackMap - creates a position map <position offset, time> indicating the
     2550//                      ending position of each commercial break in a recording
     2551//                      returns the number of tracks
     2552//                 
     2553/////////////////////////////////////////////////////////////////////////////
     2554
     2555int ProgramInfo::GetTrackMap ( const QString &sChanId, const QString &sStartTime, pos_time_map_t &trackMap )
     2556{
     2557
     2558    frm_dir_map_t markmap;
     2559    frm_pos_map_t posMap;
     2560    int keyframe_dist = 15;
     2561
     2562    trackMap.clear();
     2563    ProgramInfo *pInfo = ProgramInfo::GetProgramFromRecorded( sChanId, sStartTime );
     2564
     2565    if (pInfo == NULL)
     2566    {
     2567        VERBOSE( VB_UPNP, QString( "ProgramInfo::GetTrackMap - GetProgramFromRecorded( %1, %2 ) returned NULL" )
     2568                                 .arg( sChanId )
     2569                                 .arg( sStartTime ));
     2570        return 0;
     2571    }
     2572
     2573    pInfo->GetMarkupMap(markmap, MARK_COMM_END);
     2574
     2575    pInfo->GetPositionMap(posMap, MARK_GOP_START);
     2576
     2577    if ( posMap.isEmpty() ) {
     2578        pInfo->GetPositionMap(posMap, MARK_GOP_BYFRAME);
     2579        keyframe_dist = 1;
     2580    }
     2581
     2582    delete pInfo;
     2583
     2584    if ( markmap.isEmpty() || posMap.isEmpty() )
     2585    {
     2586        VERBOSE( VB_UPNP, "ProgramInfo::GetTrackMap - No Commercial End Marks.");
     2587        return 0;
     2588    }
     2589
     2590    QMap<long long, int>::Iterator i;
     2591    long long pos, j=0; time_t time;
     2592
     2593    for (i = markmap.begin(); i != markmap.end(); ++i) {
     2594        pos = i.key()/keyframe_dist;
     2595        time = (double) i.key() / 29.97; /* #frames/NTSC framerate = #seconds */
     2596        trackMap[time] = posMap[pos];
     2597        j++;
     2598    }
     2599    return j+1;
     2600}
     2601
    25472602/** \fn ProgramInfo::ReactivateRecording(void)
    25482603 *  \brief Asks the scheduler to restart this recording if possible.
    25492604 */
     
    44364491}
    44374492
    44384493/* vim: set expandtab tabstop=4 shiftwidth=4: */
     4494
  • libs/libmythupnp/httprequest.cpp

     
    44// Purpose - Http Request/Response
    55//                                                                           
    66// Created By  : David Blain                    Created On : Oct. 21, 2005
    7 // Modified By :                                Modified On:                 
     7// Modified By : Rob Gingher                      Modified On:  Jun. 13, 2007               
    88//                                                                           
    99//////////////////////////////////////////////////////////////////////////////
    1010
     
    4141
    4242static MIMETypes g_MIMETypes[] =
    4343{
     44    { "swf" , "application/futuresplash"   },
     45    { "pdf" , "application/pdf"            },
     46    { "xls" , "application/vnd.ms-excel"   },
     47    { "doc" , "application/vnd.ms-word"    },
     48    { "rm"  , "application/vnd.rn-realmedia" },
     49    { "zip" , "application/x-tar"          },
     50    { "gz"  , "application/x-tar"          },
     51    { "mid" , "audio/midi"                 },
     52    { "mp3" , "audio/mpeg"                 },
     53    { "m3u" , "audio/m3u"                  },
     54    { "wav" , "audio/wav"                  },
    4455    { "gif" , "image/gif"                  },
    4556    { "jpg" , "image/jpeg"                 },
    4657    { "png" , "image/png"                  },
     58    { "css" , "text/css"                   },
    4759    { "htm" , "text/html"                  },
    4860    { "html", "text/html"                  },
    4961    { "js"  , "text/html"                  },
    5062    { "txt" , "text/plain"                 },
    5163    { "xml" , "text/xml"                   },
    52     { "pdf" , "application/pdf"            },
    5364    { "avi" , "video/avi"                  },
    54     { "css" , "text/css"                   },
    55     { "swf" , "application/futuresplash"   },
    56     { "xls" , "application/vnd.ms-excel"   },
    57     { "doc" , "application/vnd.ms-word"    },
    58     { "mid" , "audio/midi"                 },
    59     { "mp3" , "audio/mpeg"                 },
    60     { "rm"  , "application/vnd.rn-realmedia" },
    61     { "wav" , "audio/wav"                  },
    62     { "zip" , "application/x-tar"          },
    63     { "gz"  , "application/x-tar"          },
    6465    { "mpg" , "video/mpeg"                 },
    6566    { "mpeg", "video/mpeg"                 },
    6667    { "vob",  "video/mpeg"                 },
     
    178179                        .arg( nSize );
    179180    sHeader += "\r\n";
    180181
     182//        VERBOSE(VB_UPNP, QString("HTTPRequest::BuildHeader : sHeader : %1 : ").arg(sHeader));
     183
    181184    return sHeader;
    182185}
    183186
     
    213216            break;
    214217    }
    215218
    216     // VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponse(xml/html) :%1 -> %2:")
    217     //                    .arg(GetResponseStatus())
    218     //                    .arg(GetPeerAddress()));
     219//    VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponse(xml/html) :%1 -> %2:")
     220//                        .arg(GetResponseStatus())
     221//                        .arg(GetPeerAddress()));
    219222
    220223    // ----------------------------------------------------------------------
    221224    // Make it so the header is sent with the data
     
    276279    m_eResponseType     = ResponseTypeOther;
    277280    m_sResponseTypeText = "text/plain";
    278281
    279     /*
    280         Dump request header
    281     for ( QStringMap::iterator it  = m_mapHeaders.begin();
    282                                it != m_mapHeaders.end();
    283                              ++it )
    284     { 
    285         cout << it.key() << ": " << it.data() << endl;
    286     }
    287     */
    288 
    289282    // ----------------------------------------------------------------------
    290283    // Make it so the header is sent with the data
    291284    // ----------------------------------------------------------------------
     
    302295        m_sResponseTypeText = GetMimeType( info.extension( FALSE ).lower() );
    303296
    304297        // ------------------------------------------------------------------
    305         // Get File size
     298        // Get File size - set llEnd to whole file
    306299        // ------------------------------------------------------------------
    307300
    308301        struct stat st;
     
    312305
    313306        m_nResponseStatus = 200;
    314307
    315         // ------------------------------------------------------------------
    316         // Process any Range Header
    317         // ------------------------------------------------------------------
     308        // --------------------------------------------------------------
     309        // Process bytes parameter for start and end offsets of track
     310        // --------------------------------------------------------------
    318311
     312        QString sBytes = m_mapParams[ "bytes"];
     313        if(ParseRange( sBytes, &llStart, &llEnd )) llSize = llEnd - llStart + 1;
     314
     315        // --------------------------------------------------------------
     316        // Process Range header for ff/rew -- Offset from start of track
     317        // --------------------------------------------------------------
     318
     319        long long   llOffset = 0, llDummy  = 0;
     320
    319321        bool    bRange = false;
    320         QString sRange = GetHeaderValue( "range", "" );
    321322
    322         if (sRange.length() > 0)
    323         {
    324             if ( bRange = ParseRange( sRange, llSize, &llStart, &llEnd ) )
    325             {
    326                 m_nResponseStatus = 206;
    327                 m_mapRespHeaders[ "Content-Range" ] = QString("bytes %1-%2/%3")
    328                                                               .arg( llStart )
    329                                                               .arg( llEnd   )
    330                                                               .arg( llSize  );
    331                 llSize = (llEnd - llStart) + 1;
    332             }
    333         }
     323        QString sRange = GetHeaderValue( "range", "" );
     324        bRange = ParseRange ( sRange, &llOffset, &llDummy );
     325
     326//      VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponseFile : Start/End %1-%2 Offset/Dummy %3-%4 bRange: %5")
     327//                      .arg(llStart)
     328//                      .arg(llEnd)
     329//                      .arg(llOffset)
     330//                      .arg(llDummy)
     331//                      .arg(bRange));
     332
     333        //
     334        //   Did user hit ff or rewind?  Is there a different start pos.?
     335        //
     336
     337        if ( bRange ) { /* process for partial content */
     338                m_nResponseStatus = 206;
     339                llDummy += llStart;
     340                llStart += llOffset;
     341                if( llDummy > llStart && llDummy < llEnd) llEnd = llDummy;
     342                        llSize = llEnd - llStart + 1;
     343        }
     344
     345        m_mapRespHeaders[ "Content-Range" ] = QString("bytes %1-%2/%3")
     346                                                        .arg( llStart )
     347                                                        .arg( llEnd   )
     348                                                        .arg( llSize  );
    334349       
    335350        // DSM-?20 specific response headers
    336 
    337351        if (bRange == false)
    338352            m_mapRespHeaders[ "User-Agent"    ] = "redsonic";
    339353
     
    342356        // ------------------------------------------------------------------
    343357
    344358    }
    345     else
     359    else /* file does not exist */
    346360        m_nResponseStatus = 404;
    347361
    348362    // -=>TODO: Should set "Content-Length: *" if file is still recording
     
    404418}
    405419
    406420/////////////////////////////////////////////////////////////////////////////
     421// Parse Range
     422// returns: true if a non-zero start or end range is provided
     423/////////////////////////////////////////////////////////////////////////////
     424
     425bool HTTPRequest::ParseRange( QString sRange,
     426                              long long *pllStart,
     427                              long long *pllEnd   )
     428{
     429    // ----------------------------------------------------------------------       
     430    // -=>TODO: Only handle 1 range at this time... should make work with full spec.
     431    // ----------------------------------------------------------------------       
     432
     433    if (sRange.length() == 0)
     434        return false;
     435
     436    // ----------------------------------------------------------------------       
     437    // remove any "bytes="
     438    // ----------------------------------------------------------------------       
     439
     440    int nIdx = sRange.find( QRegExp( "(\\d|\\-)") );
     441
     442    if (nIdx < 0)
     443        return false;
     444
     445    if (nIdx > 0)
     446        sRange.remove( 0, nIdx );
     447
     448    // ----------------------------------------------------------------------       
     449    // Split multiple ranges
     450    // ----------------------------------------------------------------------       
     451
     452    QStringList ranges = QStringList::split( ",", sRange );
     453
     454    if (ranges.count() == 0)
     455        return false;
     456
     457    // ----------------------------------------------------------------------       
     458    // Split first range into its components
     459    // ----------------------------------------------------------------------       
     460
     461    QStringList parts = QStringList::split( "-", ranges[0], true );
     462
     463    if (parts.count() != 2)
     464        return false;
     465
     466    if (parts[0].isNull() && parts[1].isNull())
     467        return false;
     468
     469    // ----------------------------------------------------------------------       
     470    //
     471    // ----------------------------------------------------------------------       
     472
     473    if (parts[0].isNull())
     474    {
     475        // ------------------------------------------------------------------
     476        // Does it match "-####" ? return true
     477        // ------------------------------------------------------------------
     478
     479        *pllEnd   = strtoll( parts[1], NULL, 10 );
     480    }
     481    else if (parts[1].isNull())
     482    {
     483        // ------------------------------------------------------------------
     484        // Does it match "####-"? if 0-, return false, else return true
     485        // ------------------------------------------------------------------
     486
     487        *pllStart = strtoll( parts[0], NULL, 10 );
     488
     489        if (*pllStart == 0) return false;
     490    }
     491    else
     492    {
     493        // ------------------------------------------------------------------
     494        // Must be  "####-####" return false if invalid
     495        // ------------------------------------------------------------------
     496
     497        *pllStart = strtoll( parts[0], NULL, 10 );
     498        *pllEnd   = strtoll( parts[1], NULL, 10 );
     499
     500        if (*pllStart > *pllEnd)
     501            return false;
     502    }
     503
     504    //cout << getSocketHandle() << "Range Requested " << *pllStart << " - " << *pllEnd << endl;
     505
     506    return true;
     507}
     508
     509/////////////////////////////////////////////////////////////////////////////
    407510//
    408511/////////////////////////////////////////////////////////////////////////////
    409512
     
    490593    }
    491594    else
    492595        m_response << "</" << m_sMethod << "Response>\r\n";
     596
     597//    VERBOSE(VB_UPNP, QString("HTTPRequest::FormatActionResponse : m_aBuffer: %1" ).arg(m_aBuffer));
     598
    493599}
    494600
    495601/////////////////////////////////////////////////////////////////////////////
     
    714820
    715821    try
    716822    {
    717         // Read first line to determin requestType
     823        // Read first line to determine requestType
    718824
    719825        QString sRequestLine = ReadLine( 2000 );
    720826
     
    8951001//
    8961002/////////////////////////////////////////////////////////////////////////////
    8971003
    898 bool HTTPRequest::ParseRange( QString sRange,
    899                               long long   llSize,
    900                               long long *pllStart,
    901                               long long *pllEnd   )
    902 {
    903     // ----------------------------------------------------------------------       
    904     // -=>TODO: Only handle 1 range at this time... should make work with full spec.
    905     // ----------------------------------------------------------------------       
    906 
    907     if (sRange.length() == 0)
    908         return false;
    909 
    910     // ----------------------------------------------------------------------       
    911     // remove any "bytes="
    912     // ----------------------------------------------------------------------       
    913 
    914     int nIdx = sRange.find( QRegExp( "(\\d|\\-)") );
    915 
    916     if (nIdx < 0)
    917         return false;
    918 
    919     if (nIdx > 0)
    920         sRange.remove( 0, nIdx );
    921 
    922     // ----------------------------------------------------------------------       
    923     // Split multiple ranges
    924     // ----------------------------------------------------------------------       
    925 
    926     QStringList ranges = QStringList::split( ",", sRange );
    927 
    928     if (ranges.count() == 0)
    929         return false;
    930 
    931     // ----------------------------------------------------------------------       
    932     // Split first range into its components
    933     // ----------------------------------------------------------------------       
    934 
    935     QStringList parts = QStringList::split( "-", ranges[0], true );
    936 
    937     if (parts.count() != 2)
    938         return false;
    939 
    940     if (parts[0].isNull() && parts[1].isNull())
    941         return false;
    942 
    943     // ----------------------------------------------------------------------       
    944     //
    945     // ----------------------------------------------------------------------       
    946 
    947     if (parts[0].isNull())
    948     {
    949         // ------------------------------------------------------------------
    950         // Does it match "-####"
    951         // ------------------------------------------------------------------
    952 
    953         long long llValue = strtoll( parts[1], NULL, 10 );
    954 
    955         *pllStart = llSize - llValue;
    956         *pllEnd   = llSize - 1;
    957     }
    958     else if (parts[1].isNull())
    959     {
    960         // ------------------------------------------------------------------
    961         // Does it match "####-"
    962         // ------------------------------------------------------------------
    963 
    964         *pllStart = strtoll( parts[0], NULL, 10 );
    965 
    966         if (*pllStart == 0)
    967             return false;
    968 
    969         *pllEnd   = llSize - 1;
    970     }
    971     else
    972     {
    973         // ------------------------------------------------------------------
    974         // Must be  "####-####"
    975         // ------------------------------------------------------------------
    976 
    977         *pllStart = strtoll( parts[0], NULL, 10 );
    978         *pllEnd   = strtoll( parts[1], NULL, 10 );
    979 
    980         if (*pllStart > *pllEnd)
    981             return false;
    982     }
    983 
    984     //cout << getSocketHandle() << "Range Requested " << *pllStart << " - " << *pllEnd << endl;
    985 
    986     return true;
    987 }
    988 
    989 /////////////////////////////////////////////////////////////////////////////
    990 //
    991 /////////////////////////////////////////////////////////////////////////////
    992 
    9931004void HTTPRequest::ExtractMethodFromURL()
    9941005{
    9951006    QStringList sList = QStringList::split( "/", m_sBaseUrl, false );
  • libs/libmythupnp/httprequest.h

     
    148148        QString         GetAdditionalHeaders( void );
    149149
    150150        bool            ParseRange          ( QString sRange,
    151                                               long long   llSize,
    152151                                              long long *pllStart,
    153152                                              long long *pllEnd   );
    154153
  • programs/mythbackend/mythxml.cpp

     
    44// Purpose - Html & XML status HttpServerExtension
    55//                                                                           
    66// Created By  : David Blain                    Created On : Oct. 24, 2005
    7 // Modified By :                                Modified On:                 
    8 //                                                                           
     7//
     8// Modified By : Robert Gingher                 Modified On: Jun. 5, 2007                 
     9//   * added method genm3u for commercial break tracks
     10//                                                                       
    911//////////////////////////////////////////////////////////////////////////////
    1012
    1113#include "mythxml.h"
     
    8486    if (sURI == "GetExpiring"          ) return MXML_GetExpiring;
    8587    if (sURI == "GetPreviewImage"      ) return MXML_GetPreviewImage;
    8688    if (sURI == "GetRecording"         ) return MXML_GetRecording;
     89    if (sURI == "GenM3u"               ) return MXML_GenM3u;
    8790    if (sURI == "GetVideo"             ) return MXML_GetVideo;
    8891    if (sURI == "GetMusic"             ) return MXML_GetMusic;
    8992    if (sURI == "GetConnectionInfo"    ) return MXML_GetConnectionInfo;
     
    122125                case MXML_GetPreviewImage      : GetPreviewImage( pRequest ); return true;
    123126
    124127                case MXML_GetRecording         : GetRecording   ( pThread, pRequest ); return true;
     128                case MXML_GenM3u               : GenM3u         ( pRequest ); return true;
    125129                case MXML_GetMusic             : GetMusic       ( pThread, pRequest ); return true;
    126130                case MXML_GetVideo             : GetVideo       ( pThread, pRequest ); return true;
    127131
     
    968972        // We only handle requests for local resources   
    969973
    970974        delete pInfo;
    971 
    972975        return;     
    973976    }
    974977
     
    11341137}
    11351138
    11361139/////////////////////////////////////////////////////////////////////////////
     1140//
     1141// GetRecording
    11371142//                 
    11381143/////////////////////////////////////////////////////////////////////////////
    11391144
     
    11471152    pRequest->m_nResponseStatus = 404;
    11481153
    11491154    QString sChanId   = pRequest->m_mapParams[ "ChanId"    ];
    1150     QString sStartTime= pRequest->m_mapParams[ "StartTime" ];
     1155    QString sStartTime = pRequest->m_mapParams[ "StartTime" ];
    11511156
    11521157    if (sStartTime.length() == 0)
    11531158    {
     
    11551160        return;
    11561161    }
    11571162
     1163// --------------------------------------------------------------
     1164// Process track parameter for start and end offsets of track
     1165// and set bytes parameter
     1166// --------------------------------------------------------------
     1167
     1168    int numtracks, trackno = pRequest->m_mapParams[ "track" ].toInt();
     1169    pos_time_map_t trackMap;
     1170    QString sStart, sRange;
     1171    QMap<long long, time_t>::Iterator i;
     1172    int j=0;
     1173
     1174    ProgramInfo *pInfo = ProgramInfo::GetProgramFromRecorded( sChanId, sStartTime );
     1175
     1176    numtracks=pInfo->GetTrackMap( sChanId, sStartTime, trackMap );
     1177    if (numtracks > 0 && trackno > 0 && trackno <= numtracks ) { /* is there a valid track parameter? */
     1178        sStart = "0-";
     1179        i = trackMap.begin();
     1180        if (trackno > 1) {
     1181          for(j=1 ; j<=trackno-2; j++) ++i;
     1182          sStart = QString("%1-")
     1183                        .arg(i.data());
     1184          i++;
     1185        }
     1186        sRange = sStart;
     1187        if (trackno < numtracks ) sRange = QString("%1%2")
     1188                        .arg(sStart)
     1189                        .arg(i.data());
     1190        pRequest->m_mapParams[ "bytes" ] = sRange;
     1191    }
     1192
     1193    delete pInfo;
     1194
     1195/*            VERBOSE( VB_UPNP, QString( "MythXML::GetRecording - trackno = %1; range = %2; bytes = %3" )
     1196                                 .arg( trackno )
     1197                                 .arg( sRange)
     1198                                        .arg( pRequest->m_mapParams["bytes"]));
     1199*/
     1200
    11581201    // ----------------------------------------------------------------------
    11591202    // DSM-320 & DSM-520 Special File Request for Index file of MPEG
    11601203    //
     
    12281271                                 .arg( pInfo->hostname ));
    12291272
    12301273            delete pInfo;
    1231 
    12321274            return;     
    12331275        }
    12341276
     
    12651307
    12661308/////////////////////////////////////////////////////////////////////////////
    12671309//
     1310// GenM3u
     1311//                 
    12681312/////////////////////////////////////////////////////////////////////////////
    12691313
     1314void MythXML::GenM3u ( HTTPRequest      *pRequest )
     1315{
     1316
     1317    pRequest->m_eResponseType   = ResponseTypeHTML;
     1318    pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
     1319    pRequest->m_nResponseStatus = 404;
     1320
     1321    QString sStartTime = pRequest->m_mapParams[ "StartTime" ];
     1322    QString sChanId    = pRequest->m_mapParams[ "ChanId"    ];
     1323
     1324    QDateTime dtStart = QDateTime::fromString( sStartTime, Qt::ISODate );
     1325
     1326    if (!dtStart.isValid())
     1327    {
     1328        VERBOSE( VB_UPNP, "MythXML::GenM3u - StartTime missing.");
     1329        return;
     1330    }
     1331   
     1332    QString sHostIP = gContext->GetSetting( "BackendServerIP", "localhost" );
     1333    QString sHostName = gContext->GetHostName();
     1334    QString sPort     = gContext->GetSettingOnHost( "BackendStatusPort", sHostName);
     1335    QString sRecordingUrl  = QString( "http://%1:%2/Myth/GetRecording?ChanId=%3&StartTime=%4" )
     1336                                   .arg( sHostIP )
     1337                                   .arg( sPort )
     1338                                   .arg( sChanId )
     1339                                   .arg( sStartTime );
     1340
     1341    pos_time_map_t trackMap;
     1342    ProgramInfo *pInfo = ProgramInfo::GetProgramFromRecorded( sChanId, dtStart );
     1343    int num=pInfo->GetTrackMap( sChanId, sStartTime, trackMap);
     1344    delete pInfo;
     1345
     1346    if( num == 0) return;
     1347
     1348    for (int i = 1; i <= num; ++i)
     1349        pRequest->m_response << QString("%1&track=%2\r\n" )
     1350                                 .arg( sRecordingUrl )
     1351                                 .arg( i );
     1352
     1353    pRequest->m_eResponseType     = ResponseTypeOther;
     1354    pRequest->m_sFileName = "GenM3u.m3u";
     1355    pRequest->m_sResponseTypeText = pRequest->GetMimeType( "m3u" );
     1356    pRequest->m_nResponseStatus   = 200;
     1357
     1358/* If we need to create a file, modify this code
     1359
     1360        sFileName = QString( "%1.%2x%3.png" )
     1361                                   .arg( pRequest->m_sFileName )
     1362                                   .arg( nWidth    )
     1363                                   .arg( nHeight   );
     1364
     1365    // ----------------------------------------------------------------------
     1366    // check to see if image is already created.
     1367    // ----------------------------------------------------------------------
     1368
     1369    if (QFile::exists( sFileName ))
     1370    {
     1371        pRequest->m_eResponseType   = ResponseTypeFile;
     1372        pRequest->m_nResponseStatus = 200;
     1373        pRequest->m_sFileName = sFileName;
     1374        return;
     1375    }
     1376
     1377    float fAspect = 0.0;
     1378
     1379    QImage *pImage = new QImage(pRequest->m_sFileName);
     1380
     1381    if (!pImage)
     1382        return;
     1383
     1384    if (fAspect <= 0)
     1385           fAspect = (float)(pImage->width()) / pImage->height();
     1386
     1387    if ( nWidth == 0 )
     1388        nWidth = (int)rint(nHeight * fAspect);
     1389
     1390    if ( nHeight == 0 )
     1391        nHeight = (int)rint(nWidth / fAspect);
     1392
     1393    QImage img = pImage->smoothScale( nWidth, nHeight);
     1394
     1395    img.save( sFileName.ascii(), "PNG" );
     1396
     1397    delete pImage;
     1398
     1399    pRequest->m_sFileName = sFileName;
     1400*/
     1401}
     1402
     1403
     1404/////////////////////////////////////////////////////////////////////////////
     1405//
     1406/////////////////////////////////////////////////////////////////////////////
     1407
    12701408void MythXML::GetMusic( HttpWorkerThread *pThread,
    12711409                        HTTPRequest      *pRequest )
    12721410{
     
    16131751}
    16141752
    16151753// vim:set shiftwidth=4 tabstop=4 expandtab:
     1754
  • programs/mythbackend/mediaserver.cpp

     
    125125                                       "http-get:*:image/png:*,"
    126126                                       "http-get:*:video/avi:*,"
    127127                                       "http-get:*:audio/mpeg:*,"
     128                                       "http-get:*:audio/m3u:*,"
    128129                                       "http-get:*:audio/wav:*,"
    129130                                       "http-get:*:video/mpeg:*,"
    130131                                       "http-get:*:video/nupplevideo:*,"
  • programs/mythbackend/upnpcdstv.cpp

     
    44// Purpose - uPnp Content Directory Extention for Recorded TV 
    55//                                                                           
    66// Created By  : David Blain                    Created On : Jan. 24, 2005
    7 // Modified By :                                Modified On:                 
     7// Modified By : Robert Gingher                 Modified On: Jun. 11, 2007
     8// *** added commercial free playlist ***                 
    89//                                                                           
    910//////////////////////////////////////////////////////////////////////////////
    1011
     
    1920
    2021/*
    2122   Recordings                              RecTv
    22     - All Programs                         RecTv/All
    23       + <recording 1>                      RecTv/All/item?ChanId=1004&StartTime=2006-04-06T20:00:00
     23    - All Programs                         RecTv/0
     24      + <recording 1>                      RecTv/0/item?ChanId=1004&StartTime=2006-04-06T20:00:00
    2425      + <recording 2>
    2526      + <recording 3>
    26     - By Title                             RecTv/title
    27       - <title 1>                          RecTv/title/key=Stargate SG-1
    28         + <recording 1>                    RecTv/title/key=Stargate SG-1/item?ChanId=1004&StartTime=2006-04-06T20:00:00
     27
     28    - Commercial Free                     RecTv/1
     29      - <recording 1>                      RecTv/1/key=1004@2006-04-06T20:00:00
     30        + <track 1>                       RecTv/1/key=1004@2006-04-06T20:00:00/item?ChanId=1004&StartTime=2006-04-06T20:00:00&track=1
     31        + <track 2>                        RecTv/1/key=1004@2006-04-06T20:00:00/item?ChanId=1004&StartTime=2006-04-06T20:00:00&track=2
     32
     33    - By Title                             RecTv/2
     34      - <title 1>                          RecTv/2/key=Stargate SG-1
     35        + <recording 1>                    RecTv/2/key=Stargate SG-1/item?ChanId=1004&StartTime=2006-04-06T20:00:00
    2936        + <recording 2>
     37
    3038    - By Genre
    3139    - By Date
    3240    - By Channel
    33     - By Group
     41    - By Recording Group
    3442*/
    3543
    3644
     
    3947    {   "All Recordings",
    4048        "*",
    4149        "SELECT 0 as key, "
    42           "CONCAT( title, ': ', subtitle) as name, "
     50          "CONCAT( DATE_FORMAT(starttime, '%Y/%m/%d'),' ',title,': ', subtitle) as name, "
    4351          "1 as children "
    4452            "FROM recorded "
    4553            "%1 "
    46             "ORDER BY starttime DESC",
     54            "ORDER BY name DESC",
    4755        "" },
    4856
     57    {   "Commercial Free",
     58        "CONCAT(chanid, '@', starttime)",
     59        "SELECT CONCAT(chanid, '@', starttime) as id, "
     60         "CONCAT( DATE_FORMAT(starttime, '%Y/%m/%d'),' ',title,': ', subtitle) as name, "
     61          "count( commflagged ) as children "
     62            "FROM recorded "
     63                "WHERE commflagged = 1 "
     64            "%1 "
     65            "GROUP BY name "
     66            "ORDER BY name DESC",
     67          "AND id = :KEY" },
     68
    4969    {   "By Title",
    5070        "title",
    5171        "SELECT title as id, "
     
    5373          "count( title ) as children "
    5474            "FROM recorded "
    5575            "%1 "
    56             "GROUP BY title "
    57             "ORDER BY title",
    58         "WHERE title=:KEY" },
     76            "GROUP BY name "
     77            "ORDER BY name",
     78        "WHERE id = :KEY" },
    5979
    6080    {   "By Genre",
    6181        "category",
     
    6484          "count( category ) as children "
    6585            "FROM recorded "
    6686            "%1 "
    67             "GROUP BY category "
    68             "ORDER BY category",
    69         "WHERE category=:KEY" },
     87            "GROUP BY name "
     88            "ORDER BY name",
     89        "WHERE id= :KEY" },
    7090
    7191    {   "By Date",
    7292        "DATE_FORMAT(starttime, '%Y-%m-%d')",
    7393        "SELECT  DATE_FORMAT(starttime, '%Y-%m-%d') as id, "
    74           "DATE_FORMAT(starttime, '%Y-%m-%d %W') as name, "
     94          "CONCAT('Recorded on ',DATE_FORMAT(starttime, '%m/%d/%Y')) as name, "
    7595          "count( DATE_FORMAT(starttime, '%Y-%m-%d %W') ) as children "
    7696            "FROM recorded "
    7797            "%1 "
    7898            "GROUP BY name "
    7999            "ORDER BY starttime DESC",
    80         "WHERE DATE_FORMAT(starttime, '%Y-%m-%d') =:KEY" },
     100        "WHERE id = :KEY" },
    81101
    82102    {   "By Channel",
    83103        "chanid",
    84104        "SELECT channel.chanid as id, "
    85           "CONCAT(channel.channum, ' ', channel.callsign) as name, "
     105          "CONCAT('Channel ',channel.channum, ' ', channel.callsign) as name, "
    86106          "count( channum ) as children "
    87107            "FROM channel "
    88108                "INNER JOIN recorded ON channel.chanid = recorded.chanid "
    89109            "%1 "
    90110            "GROUP BY name "
    91             "ORDER BY channel.chanid",
    92         "WHERE channel.chanid=:KEY" },
     111            "ORDER BY id",
     112        "WHERE id = :KEY" },
    93113
    94114
    95115    {   "By Group",
     
    98118          "recgroup as name, count( recgroup ) as children "
    99119            "FROM recorded "
    100120            "%1 "
    101             "GROUP BY recgroup "
    102             "ORDER BY recgroup",
    103         "WHERE recgroup=:KEY" }
     121            "GROUP BY name "
     122            "ORDER BY name",
     123        "WHERE id = :KEY" }
    104124};
    105125
    106126int UPnpCDSTv::g_nRootCount = sizeof( g_RootNodes ) / sizeof( UPnpCDSRootInfo );
     
    168188
    169189/////////////////////////////////////////////////////////////////////////////
    170190//
     191// AddItem()
     192//
    171193/////////////////////////////////////////////////////////////////////////////
    172194
    173195void UPnpCDSTv::AddItem( const QString           &sObjectId,
     
    175197                         bool                     bAddRef,
    176198                         MSqlQuery               &query )
    177199{
    178     int            nChanid      = query.value( 0).toInt();
     200    int      nChanId      = query.value( 0).toInt();
    179201    QDateTime      dtStartTime  = query.value( 1).toDateTime();
    180202    QDateTime      dtEndTime    = query.value( 2).toDateTime();
    181203    QString        sTitle       = query.value( 3).toString();
     
    186208    QString        sRecGroup    = query.value( 8).toString();
    187209    long long      nFileSize    = stringToLongLong( query.value( 9).toString() );
    188210    QString        sBaseName    = query.value(10).toString();
    189 
    190211    QDateTime      dtProgStart  = query.value(11).toDateTime();
    191212    QDateTime      dtProgEnd    = query.value(12).toDateTime();
    192213
     
    204225    // Build Support Strings
    205226    // ----------------------------------------------------------------------
    206227
    207     QString sName      = sTitle + ": " + sSubtitle;
     228    QStringList idPath = QStringList::split( "/", sObjectId.section('=',0,0) );
     229    bool commflag = (idPath[1] == "1");
    208230
    209231    QString sURIBase   = QString( "http://%1:%2/Myth/" )
    210232                            .arg( m_mapBackendIp  [ sHostName ] )
    211233                            .arg( m_mapBackendPort[ sHostName ] );
    212234
    213     QString sURIParams = QString( "?ChanId=%1&amp;StartTime=%2" )
    214                             .arg( nChanid )
     235    QString sName      = sTitle + ": " + sSubtitle;
     236
     237    QString sURIParams = QString( "?ChanId=%1&StartTime=%2" )
     238                            .arg( nChanId )
    215239                            .arg( dtStartTime.toString(Qt::ISODate));
    216240
    217     QString sId        = QString( "%1/item%2")
    218                             .arg( sObjectId )
    219                             .arg( sURIParams );
     241    QString sStartTime = query.value(1).toString();
     242    pos_time_map_t trackMap;
     243    ProgramInfo *pInfo = ProgramInfo::GetProgramFromRecorded( QString("%1").arg(nChanId), sStartTime );
     244    int num=0;
     245    time_t uiStart, uiEnd=0;
     246    QMap<long long, time_t>::Iterator i;
     247    long long llSize, llStartPos, llEndPos=0;
    220248
    221     CDSObject *pItem   = CDSObject::CreateVideoItem( sId,
    222                                                      sName,
    223                                                      sObjectId );
    224     pItem->m_bRestricted  = false;
    225     pItem->m_bSearchable  = true;
    226     pItem->m_sWriteStatus = "WRITABLE";
     249    if (pInfo != NULL && commflag) {
     250        num=pInfo->GetTrackMap( QString("%1").arg(nChanId), sStartTime, trackMap);
     251        i = trackMap.begin();
     252        delete pInfo;
     253        pResults->m_nTotalMatches = num;
     254    }
    227255
    228     if ( bAddRef )
     256    if (!commflag) num = 1;
     257
     258    if( num == 0) return;
     259
     260    for (int trackno = 1; trackno <= num; ++trackno )
    229261    {
    230         QString sRefId = QString( "%1/0/item%2")
    231                             .arg( m_sExtensionId )
    232                             .arg( sURIParams     );
     262        QString sTrackParam = QString("&track=%1").arg(trackno);
     263        QString sTrackName = QString(" track %1").arg(trackno);
    233264
    234         pItem->SetPropValue( "refID", sRefId );
    235     }
     265        if ( !commflag ) {
     266            sTrackParam = "";
     267            sTrackName = "";
     268        }
    236269
    237     pItem->SetPropValue( "genre"          , sCategory    );
    238     pItem->SetPropValue( "longDescription", sDescription );
    239     pItem->SetPropValue( "description"    , sSubtitle    );
     270        QString sId        = QString( "%1/item%2%3")
     271                            .arg( sObjectId )
     272                            .arg( sURIParams )
     273                            .arg( sTrackParam );
     274        CDSObject *pItem   = CDSObject::CreateVideoItem( sId, QString("%1%2").arg(sName).arg(sTrackName), sObjectId);
    240275
    241     //pItem->SetPropValue( "producer"       , );
    242     //pItem->SetPropValue( "rating"         , );
    243     //pItem->SetPropValue( "actor"          , );
    244     //pItem->SetPropValue( "director"       , );
    245     //pItem->SetPropValue( "publisher"      , );
    246     //pItem->SetPropValue( "language"       , );
    247     //pItem->SetPropValue( "relation"       , );
    248     //pItem->SetPropValue( "region"         , );
     276        pItem->m_bRestricted  = false;
     277        pItem->m_bSearchable  = true;
     278        pItem->m_sWriteStatus = "WRITABLE";
    249279
    250     // ----------------------------------------------------------------------
    251     // Needed for Microsoft Media Player Compatibility
    252     // (Won't display correct Title without them)
    253     // ----------------------------------------------------------------------
     280        if ( bAddRef )
     281        {
     282            QString sRefId = QString( "%1/0/item%2%3")
     283                              .arg( m_sExtensionId )
     284                              .arg( sURIParams     )
     285                              .arg(sTrackParam);
    254286
    255     pItem->SetPropValue( "creator"       , "[Unknown Author]" );
    256     pItem->SetPropValue( "artist"        , "[Unknown Author]" );
    257     pItem->SetPropValue( "album"         , "[Unknown Series]" );
    258     pItem->SetPropValue( "actor"         , "[Unknown Author]" );
     287            pItem->SetPropValue( "refID", sRefId );
     288        }
    259289
    260     pResults->Add( pItem );
     290        pItem->SetPropValue( "genre"          , sCategory    );
     291        pItem->SetPropValue( "longDescription", sDescription );
     292        pItem->SetPropValue( "description"    , sSubtitle    );
    261293
    262     // ----------------------------------------------------------------------
    263     // Add Video Resource Element based on File extension (HTTP)
    264     // ----------------------------------------------------------------------
    265    
    266     QFileInfo fInfo( sBaseName );
     294        // ----------------------------------------------------------------------
     295        // Needed for Microsoft Media Player Compatibility
     296        // (Won't display correct Title without them)
     297        // ----------------------------------------------------------------------
     298        pItem->SetPropValue( "creator"       , "[Unknown Author]" );
     299        pItem->SetPropValue( "artist"        , "[Unknown Author]" );
     300        pItem->SetPropValue( "album"         , "[Unknown Series]" );
     301        pItem->SetPropValue( "actor"         , "[Unknown Author]" );
    267302
    268     QString sMimeType = HTTPRequest::GetMimeType( fInfo.extension( FALSE ));
    269     // DLNA string below is temp fix for ps3 seeking.
    270     QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.OR G_FLAGS=01500000000000000000000000000000" ).arg( sMimeType  );
    271     QString sURI      = QString( "%1GetRecording%2").arg( sURIBase   )
    272                                                     .arg( sURIParams );
     303        pResults->Add( pItem );
    273304
    274     Resource *pRes = pItem->AddResource( sProtocol, sURI );
     305        // ----------------------------------------------------------------------
     306        // Add Video Resource Element/Playlist based on File extension (HTTP)
     307        // ----------------------------------------------------------------------
    275308
    276     uint uiStart = dtProgStart.toTime_t();
    277     uint uiEnd   = dtProgEnd.toTime_t();
    278     uint uiDur   = uiEnd - uiStart;
     309        QFileInfo fInfo( sBaseName );
     310        QString sMimeType = HTTPRequest::GetMimeType( fInfo.extension( FALSE ));
     311        // DLNA string below is temp fix for ps3 seeking.
     312        QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.OR G_FLAGS=01500000000000000000000000000000" ).arg( sMimeType  );
     313        QString sURI      = QString( "%1GetRecording%2%3").arg( sURIBase   )
     314                                                          .arg( sURIParams )
     315                                                          .arg(sTrackParam);
    279316
     317        Resource *pRes = pItem->AddResource( sProtocol, sURI );
    280318
    281     QString sDur = QString( "%1:%2:%3" )
    282                     .arg( (uiDur / 3600) % 24, 2 )
    283                     .arg( (uiDur / 60) % 60  , 2 )
    284                     .arg(  uiDur % 60        , 2 );
     319        if ( !commflag ) {
     320          uiStart = dtProgStart.toTime_t();
     321          uiEnd   = dtProgEnd.toTime_t();
     322          llSize = nFileSize;
     323        } else {
     324          uiStart = uiEnd;
     325          llStartPos = llEndPos;
     326          llEndPos = i.data();
     327          uiEnd = i.key();
     328          if (trackno == num) {
     329                uiEnd = dtProgEnd.toTime_t() - dtProgStart.toTime_t();
     330                llEndPos = nFileSize;
     331          }
     332          llSize = llEndPos - llStartPos;
     333        }
    285334
    286     pRes->AddAttribute( "duration"  , sDur      );
    287     pRes->AddAttribute( "size"      , longLongToString( nFileSize) );
     335/*      VERBOSE( VB_UPNP, QString( "UpnpCDSTv::AddItem() - Id %1 start = %2 end = %3 size = %4" )
     336                                       .arg( sId )
     337                                       .arg( uiStart )
     338                                       .arg( uiEnd )
     339                                       .arg( llSize ));
     340*/
     341        time_t uiDur = uiEnd - uiStart;
    288342
    289 /*
    290     // ----------------------------------------------------------------------
    291     // Add Video Resource Element based on File extension (mythtv)
    292     // ----------------------------------------------------------------------
     343        QString sDur = QString( "%1:%2:%3" )
     344                      .arg( (uiDur / 3600) % 24, 2 )
     345                      .arg( (uiDur / 60) % 60  , 2 )
     346                      .arg(  uiDur % 60        , 2 );
    293347
    294     sProtocol = QString( "myth:*:%1:*"     ).arg( sMimeType  );
    295     sURI      = QString( "myth://%1/%2" )
    296                    .arg( m_mapBackendIp  [ sHostName ] )
    297                    .arg( sBaseName );
     348        pRes->AddAttribute( "duration"  , sDur      );
     349        pRes->AddAttribute( "size"      , longLongToString( llSize ) );
    298350
    299     pRes = pItem->AddResource( sProtocol, sURI );
     351        // ----------------------------------------------------------------------
     352        // Add Thumbnail Resource
     353        // ----------------------------------------------------------------------
    300354
    301     pRes->AddAttribute( "duration"  , sDur      );
    302     pRes->AddAttribute( "size"      , longLongToString( nFileSize) );
    303 */
    304     // ----------------------------------------------------------------------
    305     // Add Thumbnail Resource
    306     // ----------------------------------------------------------------------
     355        //sURI = QString( "%1GetPreviewImage%2").arg( sURIBase   )
     356        //                                      .arg( sURIParams );
    307357
    308     //sURI = QString( "%1GetPreviewImage%2").arg( sURIBase   )
    309     //                                      .arg( sURIParams );
     358        //pItem->AddResource( "http-get:*:image/png:*" , sURI );
    310359
    311     //pItem->AddResource( "http-get:*:image/png:*" , sURI );
     360        if(commflag) ++i;
     361  } /* for */
    312362
    313363}
    314364
  • programs/mythbackend/mythxml.h

     
    44// Purpose - Myth XML protocol HttpServerExtension
    55//                                                                           
    66// Created By  : David Blain                    Created On : Oct. 24, 2005
    7 // Modified By :                                Modified On:                  
     7// Modified By : R. Gingher                     Modified On: Jun. 5, 2007                 
    88//                                                                           
    99//////////////////////////////////////////////////////////////////////////////
    1010
     
    4444    MXML_GetPreviewImage        =  9,
    4545
    4646    MXML_GetRecording           = 10,
    47     MXML_GetMusic               = 11,
     47    MXML_GenM3u                 = 11,
     48    MXML_GetMusic               = 12,
    4849
    49     MXML_GetExpiring            = 12,
    50     MXML_GetProgramDetails      = 13,
    51     MXML_GetVideo               = 14,
     50    MXML_GetExpiring            = 13,
     51    MXML_GetProgramDetails      = 14,
     52    MXML_GetVideo               = 15,
    5253
    53     MXML_GetConnectionInfo      = 15,
    54     MXML_GetAlbumArt            = 16
     54    MXML_GetConnectionInfo      = 16,
     55    MXML_GetAlbumArt            = 17
    5556
    5657} MythXMLMethod;
    5758
     
    114115        void    GetRecording   ( HttpWorkerThread *pThread,
    115116                                 HTTPRequest      *pRequest );
    116117
     118        void    GenM3u         ( HTTPRequest      *pRequest );
     119
     120
    117121        void    GetMusic       ( HttpWorkerThread *pThread,
    118122                                 HTTPRequest      *pRequest );
    119123
    120124        void    GetVideo       ( HttpWorkerThread *pThread,
    121125                                 HTTPRequest      *pRequest );
    122126
     127        void    GetDeviceDesc  ( HTTPRequest *pRequest );
    123128
    124         void    GetDeviceDesc  ( HTTPRequest *pRequest );
    125129        void    GetFile        ( HTTPRequest *pRequest, QString sFileName );
    126130
    127131    public:
     
    130134
    131135        bool     ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest );
    132136
     137         int       TrackEndMap ( QString sChanId, QDateTime dtStart, frm_pos_map_t &trackMap );
     138
    133139        // Static methods shared with HttpStatus
    134140
    135141        static void FillProgramInfo ( QDomDocument *pDoc,
  • programs/mythbackend/upnpcdsmusic.cpp

     
    130130//
    131131/////////////////////////////////////////////////////////////////////////////
    132132
    133 QString UPnpCDSMusic::GetTableName( QString sColumn )
     133QString UPnpCDSMusic::GetTableName( QString /* sColumn */)
    134134{
    135135    return "music_songs song";
    136136}