Ticket #3580: patchfile.2

File patchfile.2, 22.2 KB (added by robsbox@…, 12 years ago)
Line 
1Index: libs/libmythupnp/httprequest.cpp
2===================================================================
3--- libs/libmythupnp/httprequest.cpp    (revision 13462)
4+++ libs/libmythupnp/httprequest.cpp    (working copy)
5@@ -4,7 +4,7 @@
6 // Purpose - Http Request/Response
7 //                                                                           
8 // Created By  : David Blain                   Created On : Oct. 21, 2005
9-// Modified By :                                Modified On:                 
10+// Modified By : Rob Gingher                      Modified On:  Jun. 4, 2007               
11 //                                                                           
12 //////////////////////////////////////////////////////////////////////////////
13 
14@@ -41,26 +41,27 @@
15 
16 static MIMETypes g_MIMETypes[] =
17 {
18+    { "swf" , "application/futuresplash"   },
19+    { "pdf" , "application/pdf"            },
20+    { "xls" , "application/vnd.ms-excel"   },
21+    { "doc" , "application/vnd.ms-word"    },
22+    { "rm"  , "application/vnd.rn-realmedia" },
23+    { "zip" , "application/x-tar"          },
24+    { "gz"  , "application/x-tar"          },
25+    { "mid" , "audio/midi"                 },
26+    { "mp3" , "audio/mpeg"                 },
27+    { "m3u" , "audio/x-mpegurl"            },
28+    { "wav" , "audio/wav"                  },
29     { "gif" , "image/gif"                  },
30     { "jpg" , "image/jpeg"                 },
31     { "png" , "image/png"                  },
32+    { "css" , "text/css"                   },
33     { "htm" , "text/html"                  },
34     { "html", "text/html"                  },
35     { "js"  , "text/html"                  },
36     { "txt" , "text/plain"                 },
37     { "xml" , "text/xml"                   },
38-    { "pdf" , "application/pdf"            },
39     { "avi" , "video/avi"                  },
40-    { "css" , "text/css"                   },
41-    { "swf" , "application/futuresplash"   },
42-    { "xls" , "application/vnd.ms-excel"   },
43-    { "doc" , "application/vnd.ms-word"    },
44-    { "mid" , "audio/midi"                 },
45-    { "mp3" , "audio/mpeg"                 },
46-    { "rm"  , "application/vnd.rn-realmedia" },
47-    { "wav" , "audio/wav"                  },
48-    { "zip" , "application/x-tar"          },
49-    { "gz"  , "application/x-tar"          },
50     { "mpg" , "video/mpeg"                 },
51     { "mpeg", "video/mpeg"                 },
52     { "vob",  "video/mpeg"                 },
53@@ -213,9 +214,9 @@
54             break;
55     }
56 
57-    // VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponse(xml/html) :%1 -> %2:")
58-    //                    .arg(GetResponseStatus())
59-    //                    .arg(GetPeerAddress()));
60+//     VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponse(xml/html) :%1 -> %2:")
61+//                        .arg(GetResponseStatus())
62+//                        .arg(GetPeerAddress()));
63 
64     // ----------------------------------------------------------------------
65     // Make it so the header is sent with the data
66@@ -271,16 +272,6 @@
67     m_eResponseType     = ResponseTypeOther;
68     m_sResponseTypeText = "text/plain";
69 
70-    /*
71-        Dump request header
72-    for ( QStringMap::iterator it  = m_mapHeaders.begin();
73-                               it != m_mapHeaders.end();
74-                             ++it )
75-    { 
76-        cout << it.key() << ": " << it.data() << endl;
77-    }
78-    */
79-
80     // ----------------------------------------------------------------------
81     // Make it so the header is sent with the data
82     // ----------------------------------------------------------------------
83@@ -297,7 +288,7 @@
84         m_sResponseTypeText = GetMimeType( info.extension( FALSE ).lower() );
85 
86         // ------------------------------------------------------------------
87-        // Get File size
88+        // Get File size - set llEnd to whole file
89         // ------------------------------------------------------------------
90 
91         struct stat st;
92@@ -306,42 +297,50 @@
93             llSize = llEnd = st.st_size;
94 
95         m_nResponseStatus = 200;
96+        QString sUserAgent = GetHeaderValue( "User-Agent", "");
97 
98-        // ------------------------------------------------------------------
99-        // The Content-Range header is apparently a problem for the
100-        // AVeL LinkPlayer2 and probably other hardware players with
101-        // Syabas firmware.
102-        //
103-        // -=>TODO: Need conformation
104-        // ------------------------------------------------------------------
105+        // --------------------------------------------------------------
106+        // Process bytes parameter for start and end offsets of track
107+        // --------------------------------------------------------------
108 
109         bool    bRange     = false;
110-        QString sUserAgent = GetHeaderValue( "User-Agent", "");
111+        QString sBytes = m_mapParams[ "bytes"];
112+        long long   llOffset = 0, llDummy  = 0;
113 
114-        if ( sUserAgent.contains( "Syabas", false ) == 0 )
115-        {
116-            // --------------------------------------------------------------
117-            // Process any Range Header
118-            // --------------------------------------------------------------
119+        ParseRange ( sBytes, &llStart, &llEnd );
120 
121-            QString sRange = GetHeaderValue( "range", "" );
122+        // --------------------------------------------------------------
123+        // Process Range header for ff/rew -- Offset from start of track
124+        // --------------------------------------------------------------
125 
126-            if (sRange.length() > 0)
127-            {
128-                if ( bRange = ParseRange( sRange, llSize, &llStart, &llEnd ) )
129-                {
130-                    m_nResponseStatus = 206;
131-                    m_mapRespHeaders[ "Content-Range" ] = QString("bytes %1-%2/%3")
132-                                                                  .arg( llStart )
133-                                                                  .arg( llEnd   )
134-                                                                  .arg( llSize  );
135-                    llSize = (llEnd - llStart) + 1;
136-                }
137-            }
138-        }
139-       
140-        // DSM-?20 specific response headers
141+        QString sRange = GetHeaderValue( "range", "" );
142+        bRange = ParseRange ( sRange, &llOffset, &llDummy );
143+
144+//        VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponseFile : Start/End %1-%2 Offset/Dummy %3-%4 bRange: %5")
145+//                                     .arg(llStart)
146+//                                     .arg(llEnd)
147+//                                     .arg(llOffset)
148+//                                     .arg(llDummy)
149+//                                     .arg(bRange));
150 
151+        //
152+        //   Did user hit ff or rewind?  Is there a different start pos.?
153+        //
154+        if ( bRange ) { /* process for partial content */
155+              m_nResponseStatus = 206;
156+              llDummy += llStart;
157+               llStart += llOffset;
158+              if( llDummy > llStart && llDummy << llEnd) llEnd = llDummy;
159+               llSize = (llEnd - llStart) + 1;
160+        }
161+
162
163+        m_mapRespHeaders[ "Content-Range" ] = QString("bytes %1-%2/%3")
164+                                                      .arg( llStart )
165+                                                      .arg( llEnd   )
166+                                                      .arg( llSize  );
167+     
168+        // DSM-?20 specific response headers
169         if (bRange == false)
170             m_mapRespHeaders[ "User-Agent"    ] = "redsonic";
171 
172@@ -350,7 +349,7 @@
173         // ------------------------------------------------------------------
174 
175     }
176-    else
177+    else /* file does not exist */
178         m_nResponseStatus = 404;
179 
180     // -=>TODO: Should set "Content-Length: *" if file is still recording
181@@ -405,6 +404,95 @@
182 }
183 
184 /////////////////////////////////////////////////////////////////////////////
185+// Parse Range
186+// returns: true if a non-zero start or end range is provided
187+/////////////////////////////////////////////////////////////////////////////
188+
189+bool HTTPRequest::ParseRange( QString sRange,
190+                              long long *pllStart,
191+                              long long *pllEnd   )
192+{
193+    // ----------------------------------------------------------------------       
194+    // -=>TODO: Only handle 1 range at this time... should make work with full spec.
195+    // ----------------------------------------------------------------------       
196+
197+    if (sRange.length() == 0)
198+        return false;
199+
200+    // ----------------------------------------------------------------------       
201+    // remove any "bytes="
202+    // ----------------------------------------------------------------------       
203+
204+    int nIdx = sRange.find( QRegExp( "(\\d|\\-)") );
205+
206+    if (nIdx < 0)
207+        return false;
208+
209+    if (nIdx > 0)
210+        sRange.remove( 0, nIdx );
211+
212+    // ----------------------------------------------------------------------       
213+    // Split multiple ranges
214+    // ----------------------------------------------------------------------       
215+
216+    QStringList ranges = QStringList::split( ",", sRange );
217+
218+    if (ranges.count() == 0)
219+        return false;
220+
221+    // ----------------------------------------------------------------------       
222+    // Split first range into its components
223+    // ----------------------------------------------------------------------       
224+
225+    QStringList parts = QStringList::split( "-", ranges[0], true );
226+
227+    if (parts.count() != 2)
228+        return false;
229+
230+    if (parts[0].isNull() && parts[1].isNull())
231+        return false;
232+
233+    // ----------------------------------------------------------------------       
234+    //
235+    // ----------------------------------------------------------------------       
236+
237+    if (parts[0].isNull())
238+    {
239+        // ------------------------------------------------------------------
240+        // Does it match "-####" ? return true
241+        // ------------------------------------------------------------------
242+
243+        *pllEnd   = strtoll( parts[1], NULL, 10 );
244+    }
245+    else if (parts[1].isNull())
246+    {
247+        // ------------------------------------------------------------------
248+        // Does it match "####-"? if 0-, return false, else return true
249+        // ------------------------------------------------------------------
250+
251+        *pllStart = strtoll( parts[0], NULL, 10 );
252+
253+        if (*pllStart == 0) return false;
254+    }
255+    else
256+    {
257+        // ------------------------------------------------------------------
258+        // Must be  "####-####" return false if invalid
259+        // ------------------------------------------------------------------
260+
261+        *pllStart = strtoll( parts[0], NULL, 10 );
262+        *pllEnd   = strtoll( parts[1], NULL, 10 );
263+
264+        if (*pllStart > *pllEnd)
265+            return false;
266+    }
267+
268+    //cout << getSocketHandle() << "Range Requested " << *pllStart << " - " << *pllEnd << endl;
269+
270+    return true;
271+}
272+
273+/////////////////////////////////////////////////////////////////////////////
274 //
275 /////////////////////////////////////////////////////////////////////////////
276 
277@@ -715,7 +803,7 @@
278 
279     try
280     {
281-        // Read first line to determin requestType
282+        // Read first line to determine requestType
283 
284         QString sRequestLine = ReadLine( 2000 );
285 
286@@ -896,101 +984,6 @@
287 //
288 /////////////////////////////////////////////////////////////////////////////
289 
290-bool HTTPRequest::ParseRange( QString sRange,
291-                              long long   llSize,
292-                              long long *pllStart,
293-                              long long *pllEnd   )
294-{
295-    // ----------------------------------------------------------------------       
296-    // -=>TODO: Only handle 1 range at this time... should make work with full spec.
297-    // ----------------------------------------------------------------------       
298-
299-    if (sRange.length() == 0)
300-        return false;
301-
302-    // ----------------------------------------------------------------------       
303-    // remove any "bytes="
304-    // ----------------------------------------------------------------------       
305-
306-    int nIdx = sRange.find( QRegExp( "(\\d|\\-)") );
307-
308-    if (nIdx < 0)
309-        return false;
310-
311-    if (nIdx > 0)
312-        sRange.remove( 0, nIdx );
313-
314-    // ----------------------------------------------------------------------       
315-    // Split multiple ranges
316-    // ----------------------------------------------------------------------       
317-
318-    QStringList ranges = QStringList::split( ",", sRange );
319-
320-    if (ranges.count() == 0)
321-        return false;
322-
323-    // ----------------------------------------------------------------------       
324-    // Split first range into its components
325-    // ----------------------------------------------------------------------       
326-
327-    QStringList parts = QStringList::split( "-", ranges[0], true );
328-
329-    if (parts.count() != 2)
330-        return false;
331-
332-    if (parts[0].isNull() && parts[1].isNull())
333-        return false;
334-
335-    // ----------------------------------------------------------------------       
336-    //
337-    // ----------------------------------------------------------------------       
338-
339-    if (parts[0].isNull())
340-    {
341-        // ------------------------------------------------------------------
342-        // Does it match "-####"
343-        // ------------------------------------------------------------------
344-
345-        long long llValue = strtoll( parts[1], NULL, 10 );
346-
347-        *pllStart = llSize - llValue;
348-        *pllEnd   = llSize - 1;
349-    }
350-    else if (parts[1].isNull())
351-    {
352-        // ------------------------------------------------------------------
353-        // Does it match "####-"
354-        // ------------------------------------------------------------------
355-
356-        *pllStart = strtoll( parts[0], NULL, 10 );
357-
358-        if (*pllStart == 0)
359-            return false;
360-
361-        *pllEnd   = llSize - 1;
362-    }
363-    else
364-    {
365-        // ------------------------------------------------------------------
366-        // Must be  "####-####"
367-        // ------------------------------------------------------------------
368-
369-        *pllStart = strtoll( parts[0], NULL, 10 );
370-        *pllEnd   = strtoll( parts[1], NULL, 10 );
371-
372-        if (*pllStart > *pllEnd)
373-            return false;
374-    }
375-
376-    //cout << getSocketHandle() << "Range Requested " << *pllStart << " - " << *pllEnd << endl;
377-
378-    return true;
379-}
380-
381-/////////////////////////////////////////////////////////////////////////////
382-//
383-/////////////////////////////////////////////////////////////////////////////
384-
385 void HTTPRequest::ExtractMethodFromURL()
386 {
387     QStringList sList = QStringList::split( "/", m_sBaseUrl, false );
388Index: libs/libmythupnp/httprequest.h
389===================================================================
390--- libs/libmythupnp/httprequest.h      (revision 13462)
391+++ libs/libmythupnp/httprequest.h      (working copy)
392@@ -147,7 +147,6 @@
393         QString         GetAdditionalHeaders( void );
394 
395         bool            ParseRange          ( QString sRange,
396-                                              long long   llSize,
397                                               long long *pllStart,
398                                               long long *pllEnd   );
399 
400Index: programs/mythbackend/mythxml.cpp
401===================================================================
402--- programs/mythbackend/mythxml.cpp    (revision 13462)
403+++ programs/mythbackend/mythxml.cpp    (working copy)
404@@ -4,8 +4,10 @@
405 // Purpose - Html & XML status HttpServerExtension
406 //                                                                           
407 // Created By  : David Blain                    Created On : Oct. 24, 2005
408-// Modified By :                                Modified On:                 
409-//                                                                           
410+//
411+// Modified By : Robert Gingher                 Modified On: Jun. 5, 2007                 
412+//   * added method genm3u for commercial break tracks
413+//                                                                       
414 //////////////////////////////////////////////////////////////////////////////
415 
416 #include "mythxml.h"
417@@ -85,6 +87,7 @@
418     if (sURI == "GetExpiring"          ) return MXML_GetExpiring;
419     if (sURI == "GetPreviewImage"      ) return MXML_GetPreviewImage;
420     if (sURI == "GetRecording"         ) return MXML_GetRecording;
421+    if (sURI == "GenM3u"               ) return MXML_GenM3u;
422     if (sURI == "GetVideo"             ) return MXML_GetVideo;
423     if (sURI == "GetMusic"             ) return MXML_GetMusic;
424     if (sURI == "GetConnectionInfo"    ) return MXML_GetConnectionInfo;
425@@ -123,6 +126,7 @@
426                 case MXML_GetPreviewImage      : GetPreviewImage( pRequest ); return true;
427 
428                 case MXML_GetRecording         : GetRecording   ( pThread, pRequest ); return true;
429+                case MXML_GenM3u               : GenM3u         ( pRequest ); return true;
430                 case MXML_GetMusic             : GetMusic       ( pThread, pRequest ); return true;
431                 case MXML_GetVideo             : GetVideo       ( pThread, pRequest ); return true;
432 
433@@ -1136,6 +1140,8 @@
434 }
435 
436 /////////////////////////////////////////////////////////////////////////////
437+//
438+// GetRecording
439 //                 
440 /////////////////////////////////////////////////////////////////////////////
441 
442@@ -1267,8 +1273,94 @@
443 
444 /////////////////////////////////////////////////////////////////////////////
445 //
446+// GenM3u
447+//                 
448 /////////////////////////////////////////////////////////////////////////////
449 
450+void MythXML::GenM3u ( HTTPRequest      *pRequest )
451+{
452+
453+    pRequest->m_eResponseType   = ResponseTypeHTML;
454+    pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
455+    pRequest->m_nResponseStatus = 404;
456+
457+    QString sStartTime = pRequest->m_mapParams[ "StartTime" ];
458+    QString sChanId    = pRequest->m_mapParams[ "ChanId"    ];
459+
460+    QDateTime dtStart = QDateTime::fromString( sStartTime, Qt::ISODate );
461+
462+    if (!dtStart.isValid())
463+    {
464+        VERBOSE( VB_UPNP, "MythXML::GenM3u - StartTime missing.");
465+        return;
466+    }
467+   
468+    QString sHostIP = gContext->GetSetting( "BackendServerIP", "localhost" );
469+    QString sHostName = gContext->GetHostName();
470+    QString sPort     = gContext->GetSettingOnHost( "BackendStatusPort", sHostName);
471+    QString sRecordingUrl  = QString( "http://%1:%2/Myth/GetRecording?ChanId=%3&StartTime=%4" )
472+                                   .arg( sHostIP )
473+                                   .arg( sPort )
474+                                   .arg( sChanId )
475+                                   .arg( sStartTime );
476+
477+    ProgramInfo *pInfo = ProgramInfo::GetProgramFromRecorded( sChanId, dtStart );
478+
479+    if (pInfo == NULL)
480+    {
481+        VERBOSE( VB_UPNP, QString( "MythXML::GenM3u - GetProgramFromRecorded( %1, %2 ) returned NULL" )
482+                                 .arg( sChanId )
483+                                 .arg( sStartTime ));
484+        return;
485+    }
486+
487+    frm_dir_map_t markmap;
488+    pInfo->GetMarkupMap(markmap, MARK_COMM_END);
489+
490+    int keyframe_dist = 15;
491+
492+    frm_pos_map_t posMap;
493+    pInfo->GetPositionMap(posMap, MARK_GOP_START);
494+
495+    if ( posMap.isEmpty() ) {
496+       pInfo->GetPositionMap(posMap, MARK_GOP_BYFRAME);
497+       keyframe_dist = 1;
498+    }
499+
500+    delete pInfo;
501+
502+    if ( markmap.isEmpty() || posMap.isEmpty() )
503+    {
504+        VERBOSE( VB_UPNP, "MythXML::GenM3u - No Commercial End Marks.");
505+        return;
506+    }
507+
508+    QMap<long long, int>::Iterator i;
509+    long long pos, offset = 0;
510+
511+    for (i = markmap.begin(); i != markmap.end(); ++i) {
512+       pos = i.key()/keyframe_dist;
513+       pRequest->m_response << QString("%1&bytes=%2-%3\r\n" )
514+                                 .arg( sRecordingUrl )
515+                                 .arg( offset )
516+                                 .arg( posMap[pos]-1 ) ;
517+       offset = posMap[pos];
518+    }
519+    pRequest->m_response << QString("%1&bytes=%2-\r\n" )
520+                                 .arg( sRecordingUrl )
521+                                 .arg( offset );
522+   
523+
524+    pRequest->m_eResponseType     = ResponseTypeOther;
525+    pRequest->m_sFileName = "GenM3u.m3u";
526+    pRequest->m_sResponseTypeText = pRequest->GetMimeType( "m3u" );
527+    pRequest->m_nResponseStatus   = 200;
528+}
529+
530+/////////////////////////////////////////////////////////////////////////////
531+//
532+/////////////////////////////////////////////////////////////////////////////
533+
534 void MythXML::GetMusic( HttpWorkerThread *pThread,
535                         HTTPRequest      *pRequest )
536 {
537Index: programs/mythbackend/mythxml.h
538===================================================================
539--- programs/mythbackend/mythxml.h      (revision 13462)
540+++ programs/mythbackend/mythxml.h      (working copy)
541@@ -4,7 +4,7 @@
542 // Purpose - Myth XML protocol HttpServerExtension
543 //                                                                           
544 // Created By  : David Blain                    Created On : Oct. 24, 2005
545-// Modified By :                                Modified On:                 
546+// Modified By : R. Gingher                     Modified On: Jun. 5, 2007                 
547 //                                                                           
548 //////////////////////////////////////////////////////////////////////////////
549 
550@@ -44,14 +44,15 @@
551     MXML_GetPreviewImage        =  9,
552 
553     MXML_GetRecording           = 10,
554-    MXML_GetMusic               = 11,
555+    MXML_GenM3u                 = 11,
556+    MXML_GetMusic               = 12,
557 
558-    MXML_GetExpiring            = 12,
559-    MXML_GetProgramDetails      = 13,
560-    MXML_GetVideo               = 14,
561+    MXML_GetExpiring            = 13,
562+    MXML_GetProgramDetails      = 14,
563+    MXML_GetVideo               = 15,
564 
565-    MXML_GetConnectionInfo      = 15,
566-    MXML_GetAlbumArt            = 16
567+    MXML_GetConnectionInfo      = 16,
568+    MXML_GetAlbumArt            = 17
569 
570 } MythXMLMethod;
571 
572@@ -114,14 +115,17 @@
573         void    GetRecording   ( HttpWorkerThread *pThread,
574                                  HTTPRequest      *pRequest );
575 
576+        void    GenM3u         ( HTTPRequest      *pRequest );
577+
578+
579         void    GetMusic       ( HttpWorkerThread *pThread,
580                                  HTTPRequest      *pRequest );
581 
582         void    GetVideo       ( HttpWorkerThread *pThread,
583                                  HTTPRequest      *pRequest );
584 
585+        void    GetDeviceDesc  ( HTTPRequest *pRequest );
586 
587-        void    GetDeviceDesc  ( HTTPRequest *pRequest );
588         void    GetFile        ( HTTPRequest *pRequest, QString sFileName );
589 
590     public: