Skip to content
This repository

[Feature] Loading/Play external audio tracks #1337

Closed
wants to merge 5 commits into from

5 participants

Andreas Zelend Memphiz Damian Huckle Matthias Kortstiege Michal Piechowiak
Andreas Zelend
Collaborator

This PR adds the possibility to play external audio tracks together with video files and stacked videos.
At the moment the files have to be placed either in the same directory or in a subdirectory named "audio" or "tracks". The files can also be zipped or rared.
The recognised file extensions are read from g_settings.m_musicExtensions.

This closes ticket http://trac.xbmc.org/ticket/11446 .

Andreas Zelend
Collaborator

@sialivi I added it here SHA: ab3b950 . If you know some more please post them in the forum.

Memphiz
Owner

All in all its pretty hard to review. You should resquash into logical commits.

Andreas Zelend
Collaborator

Will do so. Should I close this one and open a new one or can this be done in the same one? (I am very unversed in git/github) Sorry!

Memphiz
Owner

This can be done in this one. Clean it up locally and then force push it to your repo ace20022/master - this will automatically update this pull request then.

Squashing can be done be either rebasing locally (git rebase HEAD~2 -i ... then prefix the second commit with "f" - this will squash the top most 2 commits into one). Its hard to give a quick howto here - but the github help is pretty good for getting the feeling on what can be done.

Damian Huckle
Collaborator

Not sure what platform you're using for dev ace20022, but if on Windows let me know - fairly easy there.

Andreas Zelend
Collaborator

I'm afraid I'll have to redo this completely from the start, since the chances are scattered all over the commits. Sorry for the mess :(

Andreas Zelend
Collaborator

Now I'm done with the reorganisation of the base feature set.

@DDDamian Thank you for offering your support! (My platform is indeed Windows)

Andreas Zelend
Collaborator

@vdrfan Will do so. Since these two methods are basically copies of the external subtitle methods, your comment is also valid for them, I guess.

Matthias Kortstiege
Collaborator

Yea, external subtitle/audio track makes no sense for live TV and the likes.

Andreas Zelend
Collaborator

I noticed that the DVDFileInfo part is not as easy as I thought at first. I will add a commit soon.

Andreas Zelend
Collaborator

I noticed that the DVDFileInfo part is not as easy as I thought at first. I will add a commit soon.

done, I altered the relevant commit itself.

Andreas Zelend
Collaborator

"." is not good filename parts delimiter - f.e. "The.Dark.Knight.Rises." will fail with this approach

Yes, it's not perfect. Imo a user who wants "nice" external audio tracks has to care for himself about it.

I think that language and "type" extraction might be done in scanforexternalaudio/subtitles methods - we could clean external audio/subtitles filename of base video filename easily and interpret what's remain as language and/or type

I also thought about diffing the the names. I have a sketch on my hd, but in the DVDFileInfo file. The problem there is that you can not easily get the video filename; more precisely I'm not sure what to do if there is more than one video stream. Furthermore, if the video is named "The.Dark.Knight.Rises.English" then the external track has to have the name "The.Dark.Knight.Rises.English.English".

Doing this in scanforexternalaudio/subtitles methods will be "nicer".

Will have a look at this asap.

Andreas Zelend
Collaborator

@pieh
I implemented the file name diffing part, but not in scanforexternal. The reason is that if we do so, we have to elevate the infos to the dvdplayer (the thumbloader part is a completely different thing, anyway).
I thought about a struct and a member vector for the dvdplayer, like

struct externalAudioTrack
{
    CDVDInputStream* m_extInputStream;
    CDVDDemux* m_extDemuxer;
    CStdString lang;
    CStdString type;
    CStdString code;
}

But then I have to rewrite almost everything. If this is a stopper for this PR I will do it after the review.

The reason why I haven't added a commit is that I found an access violation.
I use(d) CLangCodeExpander::ConvertToThreeCharCode(CStdString& strThreeCharCode,
const CStdString& strCharCode, bool localeHack /*= false*/)

to get a language code from a language name, e.g., English. The point is that this method sets the global locale of the system. I really have no clue why the method is named like this!? The crash occurs when xbmc starts and a movie with tagged ext. audio files is in the recently added list, so its maybe a thread thing.

I think the easiest way would be to parse lang. codes directly, i.e., users have to name their files accordingly like "The Matrix.eng-Commentary.ac3". What do you think?

Michal Piechowiak
Collaborator

@ace20022
In paralel to your work i'm doing something similiar for external subtitles

I added method to convert language string (being 2char code "en", 3char code "eng" or full language name "english") to 2char code: pieh@4b9cc5d

And helper method to extract language and name from filename: pieh@5789502 (i dropped idea of doing this as part of CUtil::ScanForExternalXX as we can manually point to subtitles or load subitltes from upnp resource and lang extraction would be bypassed)

What I do there is specify few regexpes to match lang and name and try to pick up best from all matches. Fact that we know if string that is recognized as lang part is actual part (testing if we can convert it to 2char code) makes this pretty accurate. I think that I would also add either white list and/or black list for stream names. Regexpes and white/black list name entries would be adjustable via advancedsettings.xml

Andreas Zelend
Collaborator

@pieh
Really great! Way better than my stuff! Is this final and is it possible to merge your commits in my branch?

Michal Piechowiak
Collaborator

This is still work in progress. For now I would just drop language extraction for external audio and would hook it up when we're both ready.

Andreas Zelend
Collaborator

As @pieh suggested, I dropped the lang/type extraction and rebased on this occasion.
I will reimplement after/if PR #1365 got merged.

Andreas Zelend
Collaborator

Just rebased. Has anyone from the team the time and interest to review this? I guess @elupus is the main dev for this part of the system, right?

Damian Huckle
Collaborator

Bump for review - @pieh, @elupus?

Andreas Zelend
Collaborator

fixed some bugs

Andreas Zelend
Collaborator

Revised version, included simplifications.

Andreas Zelend
Collaborator

@elupus does this pr has any chance at all to be merged before hell freezes? :-) If not I would like to close it.

Andreas Zelend
Collaborator

Not even 2 bytes and a few seconds left?
I know the team follows the rule to simply ignore unwanted features, but I don't think that this is right. Over 1/3 of the prs are older then 6 month and 191 opened at the moment are too much imho.

Andreas Zelend ace20022 closed this April 03, 2013
Deleted user
ghost commented April 03, 2013

The content you are editing has changed. Reload the page and try again.

please, if you reopen i'll handle it.

Sending Request…

Attach images by dragging & dropping or selecting them. Octocat-spinner-32 Uploading your images… Unfortunately, we don't support that file type. Try again with a PNG, GIF, or JPG. Yowza, that's a big file. Try again with an image file smaller than 10MB. This browser doesn't support image attachments. We recommend updating to the latest Internet Explorer, Google Chrome, or Firefox. Something went really wrong, and we can't process that image. Try again.

Andreas Zelend
Collaborator

@cptspiff Thanks for the response! I'm afraid I can't reopen it because I changed the layout of my repo.
I will open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 5 unique commits by 1 author.

Feb 06, 2013
Andreas Zelend Find external audio files, open corresponding inputStreams and store …
…them.
2d9877a
Andreas Zelend Open demuxers for external audio files. Update the SelectionStream. A…
…dapt all relevant places where m_pDemuxer is used; in particular ReadPacket(...) and add ReadExternalAudioPacket(...)
bf185f8
Andreas Zelend Adapt DVDFileInfo so that it reads infos also from external audio fil…
…es (e.g. language and channels).
e4fe9dc
Andreas Zelend Only apply Seek and SetSpeed to the actually active external demuxer …
…to speed things up.
5592fb8
Andreas Zelend Fix seeking chapters while having an ext. audio track selected.
(External) audio tracks don't have chapters, so we have to use SeekTime().
da7bd4a
This page is out of date. Refresh to see the latest.
198  xbmc/Util.cpp
@@ -2189,6 +2189,204 @@ bool CUtil::IsVobSub( const std::vector<CStdString>& vecSubtitles, const CStdStr
2189 2189
   return false;
2190 2190
 }
2191 2191
 
  2192
+
  2193
+void CUtil::ScanForExternalAudio(const CStdString& strMovie, std::vector<CStdString>& vecAudio )
  2194
+{
  2195
+  unsigned int startTimer = XbmcThreads::SystemClockMillis();
  2196
+
  2197
+  // new array for commons audio sub dirs
  2198
+  const char * common_audio_dirs[] = {"audio",
  2199
+    "tracks",
  2200
+    NULL};
  2201
+
  2202
+  CFileItem item(strMovie, false);
  2203
+  if ( item.IsInternetStream()
  2204
+   ||  item.IsHDHomeRun()
  2205
+   ||  item.IsSlingbox()
  2206
+   ||  item.IsPlayList()
  2207
+   ||  item.IsLiveTV()
  2208
+   || !item.IsVideo()) 
  2209
+    return;
  2210
+
  2211
+  vector<CStdString> strLookInPaths;
  2212
+
  2213
+  CStdString strMovieFileName;
  2214
+  CStdString strPath;
  2215
+  
  2216
+  CStdStringArray audio_exts;
  2217
+  StringUtils::SplitString(g_settings.m_musicExtensions, "|", audio_exts);
  2218
+  
  2219
+  URIUtils::Split(strMovie, strPath, strMovieFileName);
  2220
+  CStdString strMovieFileNameNoExt(URIUtils::ReplaceExtension(strMovieFileName, ""));
  2221
+  strLookInPaths.push_back(strPath);
  2222
+
  2223
+  if (strMovie.Left(6) == "rar://") // <--- if this is found in main path then ignore it!
  2224
+  {
  2225
+    CURL url(strMovie);
  2226
+    CStdString strArchive = url.GetHostName();
  2227
+    URIUtils::Split(strArchive, strPath, strMovieFileName);
  2228
+    strLookInPaths.push_back(strPath);
  2229
+  }
  2230
+
  2231
+  int iSize = strLookInPaths.size();
  2232
+  for (int i=0; i<iSize; ++i)
  2233
+  {
  2234
+    CStdStringArray directories;
  2235
+    int nTokens = StringUtils::SplitString( strLookInPaths[i], "/", directories );
  2236
+    if (nTokens == 1)
  2237
+      StringUtils::SplitString( strLookInPaths[i], "\\", directories );
  2238
+
  2239
+    // if it's inside a cdX dir, add parent path
  2240
+    if (directories.size() >= 2 && directories[directories.size()-2].size() == 3 && directories[directories.size()-2].Left(2).Equals("cd")) // SplitString returns empty token as last item, hence size-2
  2241
+    {
  2242
+      CStdString strPath2;
  2243
+      URIUtils::GetParentPath(strLookInPaths[i], strPath2);
  2244
+      strLookInPaths.push_back(strPath2);
  2245
+    }
  2246
+  }
  2247
+
  2248
+  // checking if any of the common subdirs exist ..
  2249
+  iSize = strLookInPaths.size();
  2250
+  for (int i=0;i<iSize;++i)
  2251
+  {
  2252
+    for (int j=0; common_audio_dirs[j]; j++)
  2253
+    {
  2254
+      CStdString strPath2 = URIUtils::AddFileToFolder(strLookInPaths[i],common_audio_dirs[j]);
  2255
+      if (CDirectory::Exists(strPath2))
  2256
+        strLookInPaths.push_back(strPath2);
  2257
+    }
  2258
+  }
  2259
+
  2260
+  CStdString strLExt;
  2261
+  CStdString strDest;
  2262
+  CStdString strItem;
  2263
+
  2264
+  // 2 steps for movie directory and alternate audio directory
  2265
+  CLog::Log(LOGDEBUG,"%s: Searching for audio...", __FUNCTION__);
  2266
+  for (unsigned int step = 0; step < strLookInPaths.size(); step++)
  2267
+  {
  2268
+    if (strLookInPaths[step].length() != 0)
  2269
+    {
  2270
+      CFileItemList items;
  2271
+
  2272
+      CDirectory::GetDirectory(strLookInPaths[step], items, g_settings.m_musicExtensions, DIR_FLAG_NO_FILE_DIRS);
  2273
+      int fnl = strMovieFileNameNoExt.size();
  2274
+
  2275
+      for (int j = 0; j < items.Size(); j++)
  2276
+      {
  2277
+        URIUtils::Split(items[j]->GetPath(), strPath, strItem);
  2278
+
  2279
+        if (strItem.Left(fnl).Equals(strMovieFileNameNoExt))
  2280
+        {
  2281
+          // is this a rar or zip-file
  2282
+          if (URIUtils::IsRAR(strItem) || URIUtils::IsZIP(strItem))
  2283
+          {
  2284
+            // zip-file name equals strMovieFileNameNoExt, don't check in zip-file
  2285
+            ScanArchiveForAudio( items[j]->GetPath(), "", vecAudio );
  2286
+          }
  2287
+          else    // not a rar/zip file
  2288
+          {
  2289
+            for (unsigned int i = 0; i < audio_exts.size(); i++)
  2290
+            {
  2291
+              //save audio with same name as movie
  2292
+              if (URIUtils::GetExtension(strItem).Equals(audio_exts[i]))
  2293
+              {
  2294
+                vecAudio.push_back( items[j]->GetPath() ); 
  2295
+                CLog::Log(LOGINFO, "%s: found external audio file %s\n", __FUNCTION__, items[j]->GetPath().c_str() );
  2296
+              }
  2297
+            }
  2298
+          }
  2299
+        }
  2300
+        else
  2301
+        {
  2302
+          // is this a rar or zip-file
  2303
+          if (URIUtils::IsRAR(strItem) || URIUtils::IsZIP(strItem))
  2304
+          {
  2305
+            // check strMovieFileNameNoExt in zip-file
  2306
+            ScanArchiveForAudio( items[j]->GetPath(), strMovieFileNameNoExt, vecAudio );
  2307
+          }
  2308
+        }
  2309
+      }
  2310
+    }
  2311
+  }
  2312
+  CLog::Log(LOGDEBUG,"%s: END (total time: %i ms)", __FUNCTION__, (int)(XbmcThreads::SystemClockMillis() - startTimer));
  2313
+}
  2314
+
  2315
+
  2316
+int CUtil::ScanArchiveForAudio( const CStdString& strArchivePath, const CStdString& strMovieFileNameNoExt, std::vector<CStdString>& vecAudio )
  2317
+{
  2318
+  int nAudioAdded = 0;
  2319
+  CFileItemList ItemList;
  2320
+
  2321
+  CStdStringArray audio_exts;
  2322
+  StringUtils::SplitString(g_settings.m_musicExtensions, "|", audio_exts);
  2323
+
  2324
+  // zip only gets the root dir
  2325
+  if (URIUtils::GetExtension(strArchivePath).Equals(".zip"))
  2326
+  {
  2327
+    CStdString strZipPath;
  2328
+    URIUtils::CreateArchivePath(strZipPath,"zip",strArchivePath,"");
  2329
+    if (!CDirectory::GetDirectory(strZipPath,ItemList,"",DIR_FLAG_NO_FILE_DIRS))
  2330
+      return false;
  2331
+  }
  2332
+  else
  2333
+  {
  2334
+#ifdef HAS_FILESYSTEM_RAR
  2335
+    // get _ALL_files in the rar, even those located in subdirectories because we set the bMask to false.
  2336
+    // so now we dont have to find any subdirs anymore, all files in the rar is checked.
  2337
+    if( !g_RarManager.GetFilesInRar(ItemList, strArchivePath, false, "") )
  2338
+      return false;
  2339
+#else
  2340
+    return false;
  2341
+#endif
  2342
+  }
  2343
+  for (int it= 0 ; it <ItemList.Size();++it)
  2344
+  {
  2345
+    CStdString strPathInRar = ItemList[it]->GetPath();
  2346
+    CStdString strExt = URIUtils::GetExtension(strPathInRar);
  2347
+
  2348
+    CLog::Log(LOGDEBUG, "ScanArchiveForAudio:: Found file %s", strPathInRar.c_str());
  2349
+    // always check any embedded rar archives
  2350
+    // checking for embedded rars, I moved this outside the audio_exts[] loop. We only need to check this once for each file.
  2351
+    if (URIUtils::IsRAR(strPathInRar) || URIUtils::IsZIP(strPathInRar))
  2352
+    {
  2353
+      CStdString strRarInRar;
  2354
+      if (URIUtils::GetExtension(strPathInRar).Equals(".rar"))
  2355
+        URIUtils::CreateArchivePath(strRarInRar, "rar", strArchivePath, strPathInRar);
  2356
+      else
  2357
+        URIUtils::CreateArchivePath(strRarInRar, "zip", strArchivePath, strPathInRar);
  2358
+      ScanArchiveForAudio(strRarInRar,strMovieFileNameNoExt,vecAudio);
  2359
+    }
  2360
+    // done checking if this is a rar-in-rar
  2361
+
  2362
+    // check that the found filename matches the movie filename
  2363
+    int fnl = strMovieFileNameNoExt.size();
  2364
+    if (fnl && !URIUtils::GetFileName(strPathInRar).Left(fnl).Equals(strMovieFileNameNoExt))
  2365
+      continue;
  2366
+
  2367
+    unsigned int iPos=0;
  2368
+    while (iPos < audio_exts.size())
  2369
+    {
  2370
+      if (strExt.CompareNoCase(audio_exts[iPos]) == 0)
  2371
+      {
  2372
+        CStdString strSourceUrl;
  2373
+        if (URIUtils::GetExtension(strArchivePath).Equals(".rar"))
  2374
+          URIUtils::CreateArchivePath(strSourceUrl, "rar", strArchivePath, strPathInRar);
  2375
+        else
  2376
+          strSourceUrl = strPathInRar;
  2377
+
  2378
+        CLog::Log(LOGINFO, "%s: found audio file %s\n", __FUNCTION__, strSourceUrl.c_str() );
  2379
+        vecAudio.push_back( strSourceUrl );
  2380
+        nAudioAdded++;
  2381
+      }
  2382
+
  2383
+      iPos++;
  2384
+    }
  2385
+  }
  2386
+
  2387
+  return nAudioAdded;
  2388
+}
  2389
+
2192 2390
 bool CUtil::CanBindPrivileged()
2193 2391
 {
2194 2392
 #ifdef _LINUX
2  xbmc/Util.h
@@ -88,6 +88,8 @@ class CUtil
88 88
   static int ScanArchiveForSubtitles( const CStdString& strArchivePath, const CStdString& strMovieFileNameNoExt, std::vector<CStdString>& vecSubtitles );
89 89
   static bool FindVobSubPair( const std::vector<CStdString>& vecSubtitles, const CStdString& strIdxPath, CStdString& strSubPath );
90 90
   static bool IsVobSub( const std::vector<CStdString>& vecSubtitles, const CStdString& strSubPath );  
  91
+  static void ScanForExternalAudio(const CStdString& strMovie, std::vector<CStdString>& vecAudio );
  92
+  static int ScanArchiveForAudio( const CStdString& strArchivePath, const CStdString& strMovieFileNameNoExt, std::vector<CStdString>& vecAudio );
91 93
   static int64_t ToInt64(uint32_t high, uint32_t low);
92 94
   static CStdString GetNextFilename(const CStdString &fn_template, int max);
93 95
   static CStdString GetNextPathname(const CStdString &path_template, int max);
122  xbmc/cores/dvdplayer/DVDFileInfo.cpp
@@ -49,6 +49,7 @@
49 49
 #include "DllSwScale.h"
50 50
 #include "filesystem/File.h"
51 51
 #include "TextureCache.h"
  52
+#include "Util.h"
52 53
 
53 54
 
54 55
 bool CDVDFileInfo::GetFileDuration(const CStdString &path, int& duration)
@@ -136,7 +137,7 @@ bool CDVDFileInfo::ExtractThumb(const CStdString &strPath, CTextureDetails &deta
136 137
   }
137 138
 
138 139
   if (pStreamDetails)
139  
-    DemuxerToStreamDetails(pInputStream, pDemuxer, *pStreamDetails, strPath);
  140
+    DemuxerToStreamDetails(pInputStream, pDemuxer, *pStreamDetails, true, strPath);
140 141
 
141 142
   CDemuxStream* pStream = NULL;
142 143
   int nVideoStream = -1;
@@ -315,7 +316,7 @@ bool CDVDFileInfo::GetFileStreamDetails(CFileItem *pItem)
315 316
   CDVDDemux *pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream);
316 317
   if (pDemuxer)
317 318
   {
318  
-    bool retVal = DemuxerToStreamDetails(pInputStream, pDemuxer, pItem->GetVideoInfoTag()->m_streamDetails, strFileNameAndPath);
  319
+    bool retVal = DemuxerToStreamDetails(pInputStream, pDemuxer, pItem->GetVideoInfoTag()->m_streamDetails, true, strFileNameAndPath);
319 320
     delete pDemuxer;
320 321
     delete pInputStream;
321 322
     return retVal;
@@ -327,8 +328,40 @@ bool CDVDFileInfo::GetFileStreamDetails(CFileItem *pItem)
327 328
   }
328 329
 }
329 330
 
  331
+bool CDVDFileInfo::DemuxerToStreamDetails(CDVDInputStream *pInputStream, CDVDDemux *pDemux, std::vector<CDVDDemux*> m_extDemuxer, CStreamDetails &details, const CStdString &path)
  332
+{
  333
+  bool retVal = false;
  334
+  details.Reset();
  335
+  retVal = DemuxerToStreamDetails(pInputStream, pDemux, details, false, path);
  336
+
  337
+  if(! retVal)
  338
+    return false;
  339
+
  340
+  // process external audio streams
  341
+  for (unsigned int i = 0; i < m_extDemuxer.size(); i++)
  342
+  {
  343
+    if (m_extDemuxer[i])
  344
+    {
  345
+      CDemuxStream *stream = m_extDemuxer[i]->GetStream(0);
  346
+
  347
+      if (stream->type == STREAM_AUDIO)
  348
+      {
  349
+        CStreamDetailAudio *p = new CStreamDetailAudio();
  350
+        p->m_iChannels = ((CDemuxStreamAudio *)stream)->iChannels;
  351
+        if (strlen(stream->language) > 0)
  352
+          p->m_strLanguage = stream->language;
  353
+        pDemux->GetStreamCodecName(0, p->m_strCodec);
  354
+        details.AddStream(p);
  355
+        retVal = true;
  356
+      }
  357
+    }
  358
+  }
  359
+
  360
+  details.DetermineBestStreams();
  361
+  return retVal;
  362
+}
330 363
 /* returns true if details have been added */
331  
-bool CDVDFileInfo::DemuxerToStreamDetails(CDVDInputStream *pInputStream, CDVDDemux *pDemux, CStreamDetails &details, const CStdString &path)
  364
+bool CDVDFileInfo::DemuxerToStreamDetails(CDVDInputStream *pInputStream, CDVDDemux *pDemux, CStreamDetails &details, bool handleExternalAudio, const CStdString &path)
332 365
 {
333 366
   bool retVal = false;
334 367
   details.Reset();
@@ -390,6 +423,16 @@ bool CDVDFileInfo::DemuxerToStreamDetails(CDVDInputStream *pInputStream, CDVDDem
390 423
     }
391 424
   }  /* for iStream */
392 425
 
  426
+  CStdString video_path;
  427
+  if (path.empty())
  428
+    video_path = pInputStream->GetFileName();
  429
+  else
  430
+    video_path = path;
  431
+
  432
+  // include external audio tracks
  433
+  if (handleExternalAudio)
  434
+    retVal |= AddExternalAudioToDetails(video_path, details);
  435
+
393 436
   details.DetermineBestStreams();
394 437
 #ifdef HAVE_LIBBLURAY
395 438
   // correct bluray runtime. we need the duration from the input stream, not the demuxer.
@@ -404,3 +447,76 @@ bool CDVDFileInfo::DemuxerToStreamDetails(CDVDInputStream *pInputStream, CDVDDem
404 447
   return retVal;
405 448
 }
406 449
 
  450
+bool CDVDFileInfo::AddExternalAudioToDetails(const CStdString &path, CStreamDetails &details)
  451
+{
  452
+  bool retVal = false;
  453
+  // find any available external audio track
  454
+  std::vector<CStdString> filenames;
  455
+  CUtil::ScanForExternalAudio( path, filenames );
  456
+  for(unsigned int i=0;i<filenames.size();i++)
  457
+  {
  458
+    CDVDInputStream* ext_pInputStream;
  459
+    CFileItem ext_item = CFileItem(filenames[i]);
  460
+    CStdString ext_mimeType = ext_item.GetMimeType();
  461
+    ext_pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, filenames[i], ext_mimeType);
  462
+    if(ext_pInputStream == NULL)
  463
+    {
  464
+      CLog::Log(LOGERROR, "CDVDPlayer::OpenInputStream - unable to create input stream for external audio file [%s]", filenames[i].c_str());
  465
+      continue;
  466
+    }
  467
+    else
  468
+      ext_pInputStream->SetFileItem(ext_item);
  469
+
  470
+    if (!ext_pInputStream->Open(filenames[i].c_str(), ext_mimeType))
  471
+    {
  472
+      CLog::Log(LOGERROR, "CDVDPlayer::OpenInputStream - error opening  external audio file [%s]", filenames[i].c_str());
  473
+      continue;
  474
+    }
  475
+    CDVDDemux* extDemuxer = NULL;
  476
+    try
  477
+    {
  478
+      int attempts = 10;
  479
+      while(attempts-- > 0)
  480
+      {
  481
+        extDemuxer = CDVDFactoryDemuxer::CreateDemuxer(ext_pInputStream);
  482
+        if(!extDemuxer && ext_pInputStream->NextStream() != CDVDInputStream::NEXTSTREAM_NONE)
  483
+        {
  484
+          CLog::Log(LOGDEBUG, "%s - New stream available from input, retry open", __FUNCTION__);
  485
+          continue;
  486
+        }
  487
+        break;
  488
+      }
  489
+
  490
+      if(!extDemuxer)
  491
+      {
  492
+        CLog::Log(LOGERROR, "%s - Error creating external audio demuxer for file %s", __FUNCTION__, ext_pInputStream->GetFileName().c_str());
  493
+        continue;
  494
+      }
  495
+
  496
+    }
  497
+    catch(...)
  498
+    {
  499
+      CLog::Log(LOGERROR, "%s - Exception thrown when opening external audio demuxer for file %s", __FUNCTION__, ext_pInputStream->GetFileName().c_str());
  500
+      continue;
  501
+    }
  502
+    if(extDemuxer)
  503
+    {
  504
+      //filter strange external audio files
  505
+      if(extDemuxer->GetNrOfStreams() > 1 || extDemuxer->GetStream(0)->type != STREAM_AUDIO)
  506
+        continue;
  507
+
  508
+      CDemuxStream *stream = extDemuxer->GetStream(0);
  509
+      if (stream->type == STREAM_AUDIO)
  510
+      {
  511
+        CStreamDetailAudio *p = new CStreamDetailAudio();
  512
+        p->m_iChannels = ((CDemuxStreamAudio *)stream)->iChannels;
  513
+        if (strlen(stream->language) > 0)
  514
+          p->m_strLanguage = stream->language;
  515
+        extDemuxer->GetStreamCodecName(0, p->m_strCodec);
  516
+        details.AddStream(p);
  517
+        retVal = true;
  518
+      }
  519
+    }
  520
+  }
  521
+  return retVal;
  522
+}
4  xbmc/cores/dvdplayer/DVDFileInfo.h
@@ -36,6 +36,8 @@ class CDVDFileInfo
36 36
   // Probe the files streams and store the info in the VideoInfoTag
37 37
   static bool GetFileStreamDetails(CFileItem *pItem);
38 38
   static bool DemuxerToStreamDetails(CDVDInputStream* pInputStream, CDVDDemux *pDemux, CStreamDetails &details, const CStdString &path = "");
39  
-
  39
+  static bool DemuxerToStreamDetails(CDVDInputStream* pInputStream, CDVDDemux *pDemux, std::vector<CDVDDemux*> m_extDemuxer, CStreamDetails &details, const CStdString &path = "");
  40
+  static bool DemuxerToStreamDetails(CDVDInputStream* pInputStream, CDVDDemux *pDemux, CStreamDetails &details, bool handleExternalAudio, const CStdString &path = "");
40 41
   static bool GetFileDuration(const CStdString &path, int &duration);
  42
+  static bool AddExternalAudioToDetails(const CStdString &path, CStreamDetails &details);
41 43
 };
351  xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -88,6 +88,10 @@
88 88
 using namespace std;
89 89
 using namespace PVR;
90 90
 
  91
+// remove
  92
+int rate = 50;
  93
+// remove
  94
+
91 95
 void CSelectionStreams::Clear(StreamType type, StreamSource source)
92 96
 {
93 97
   CSingleLock lock(m_section);
@@ -392,6 +396,15 @@ void CSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer)
392 396
   }
393 397
 }
394 398
 
  399
+/* Upate the selection streams with data from external audio files*/
  400
+void CSelectionStreams::UpdateExtAudio(CDVDInputStream* input, CDVDDemux* ext_demuxer)
  401
+{
  402
+  int last = m_Streams.size();
  403
+  Update(input, ext_demuxer);
  404
+  if (last < m_Streams.size())
  405
+    m_Streams[last].id =last;
  406
+}
  407
+
395 408
 CDVDPlayer::CDVDPlayer(IPlayerCallback& callback)
396 409
     : IPlayer(callback),
397 410
       CThread("CDVDPlayer"),
@@ -410,6 +423,11 @@ CDVDPlayer::CDVDPlayer(IPlayerCallback& callback)
410 423
   m_pSubtitleDemuxer = NULL;
411 424
   m_pInputStream = NULL;
412 425
 
  426
+  m_extDemuxer.clear();
  427
+  m_extInputStreams.clear();
  428
+  m_extAudio = false;
  429
+  m_extAudioOffset = 0;
  430
+
413 431
   m_dvd.Clear();
414 432
   m_State.Clear();
415 433
   m_EdlAutoSkipMarkers.Clear();
@@ -506,6 +524,12 @@ bool CDVDPlayer::CloseFile()
506 524
   if(m_pDemuxer)
507 525
     m_pDemuxer->Abort();
508 526
 
  527
+  for(unsigned int i = 0; i < m_extDemuxer.size(); i++)
  528
+  {
  529
+    if(m_extDemuxer[i])
  530
+      m_extDemuxer[i]->Abort();
  531
+  }
  532
+
509 533
   if(m_pSubtitleDemuxer)
510 534
     m_pSubtitleDemuxer->Abort();
511 535
 
@@ -544,6 +568,56 @@ void CDVDPlayer::OnStartup()
544 568
   CUtil::ClearTempFonts();
545 569
 }
546 570
 
  571
+bool CDVDPlayer::OpenExternalAudioInputStreams()
  572
+{
  573
+  if (!m_pInputStream)
  574
+    return false;
  575
+
  576
+  for(unsigned int i = 0; i < m_extInputStreams.size(); i++)
  577
+  {
  578
+    if(m_extInputStreams[i])
  579
+      SAFE_DELETE(m_extInputStreams[i]);
  580
+  }
  581
+  
  582
+  // find any available external audio track
  583
+  if (!m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
  584
+    &&  !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_TV)
  585
+    &&  !m_pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP))
  586
+  {
  587
+    std::vector<CStdString> filenames;
  588
+    CUtil::ScanForExternalAudio( m_filename, filenames );
  589
+
  590
+    if (!filenames.empty())
  591
+      CLog::Log(LOGNOTICE, "Creating InputStreams for external audio files");
  592
+
  593
+    for(unsigned int i=0;i<filenames.size();i++)
  594
+    {
  595
+      CDVDInputStream* ext_pInputStream = NULL;
  596
+      CFileItem ext_item = CFileItem(filenames[i]);
  597
+      CStdString ext_mimeType = ext_item.GetMimeType();
  598
+      ext_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, filenames[i], ext_mimeType);
  599
+      if(ext_pInputStream == NULL)
  600
+      {
  601
+        CLog::Log(LOGERROR, "CDVDPlayer::OpenInputStream - unable to create input stream for external audio file [%s]", filenames[i].c_str());
  602
+        continue;
  603
+      }
  604
+      else
  605
+        ext_pInputStream->SetFileItem(ext_item);
  606
+
  607
+      if (!ext_pInputStream->Open(filenames[i].c_str(), ext_mimeType))
  608
+      {
  609
+        CLog::Log(LOGERROR, "CDVDPlayer::OpenInputStream - error opening  external audio file [%s]", filenames[i].c_str());
  610
+        continue;
  611
+      }
  612
+      m_extInputStreams.push_back(ext_pInputStream);
  613
+    }
  614
+  }
  615
+  if(m_extInputStreams.size() == 0)
  616
+    return false;
  617
+  else
  618
+    return true;
  619
+}
  620
+
547 621
 bool CDVDPlayer::OpenInputStream()
548 622
 {
549 623
   if(m_pInputStream)
@@ -632,6 +706,94 @@ bool CDVDPlayer::OpenInputStream()
632 706
   return true;
633 707
 }
634 708
 
  709
+bool CDVDPlayer::OpenExternalAudioDemuxStreams()
  710
+{
  711
+  if(!m_pDemuxer)
  712
+    return false;
  713
+
  714
+  for(unsigned int i = 0; i < m_extDemuxer.size(); i++)
  715
+  {
  716
+    if(m_extDemuxer[i])
  717
+      SAFE_DELETE(m_extDemuxer[i]);
  718
+  }
  719
+
  720
+  m_extAudio = false;
  721
+
  722
+  CLog::Log(LOGNOTICE, "Creating external audio demuxers");
  723
+
  724
+  // store the offset for proper access to the external streams
  725
+  m_extAudioOffset = m_SelectionStreams.Count(STREAM_NONE);
  726
+
  727
+  // add any available external audio
  728
+  vector<CDVDInputStream*>::iterator iter = m_extInputStreams.begin();
  729
+  while (iter != m_extInputStreams.end())
  730
+  {
  731
+    CDVDInputStream* extInput = *iter;
  732
+    if(extInput)
  733
+    {
  734
+      CDVDDemux* extDemuxer = NULL;
  735
+      try
  736
+      {
  737
+        int attempts = 10;
  738
+        while(!m_bStop && attempts-- > 0)
  739
+        {
  740
+          extDemuxer = CDVDFactoryDemuxer::CreateDemuxer(extInput);
  741
+          if(!extDemuxer && extInput->NextStream() != CDVDInputStream::NEXTSTREAM_NONE)
  742
+          {
  743
+            CLog::Log(LOGDEBUG, "%s - New stream available from input, retry open", __FUNCTION__);
  744
+            continue;
  745
+          }
  746
+          break;
  747
+        }
  748
+
  749
+        if(!extDemuxer)
  750
+        {
  751
+          CLog::Log(LOGERROR, "%s - Error creating external audio demuxer for file %s", __FUNCTION__, extInput->GetFileName().c_str());
  752
+          
  753
+          // delete invalid InputStreams
  754
+          iter = m_extInputStreams.erase(iter);
  755
+          SAFE_DELETE(extInput);
  756
+          continue;
  757
+        }
  758
+
  759
+      }
  760
+      catch(...)
  761
+      {
  762
+        CLog::Log(LOGERROR, "%s - Exception thrown when opening external audio demuxer for file %s", __FUNCTION__, extInput->GetFileName().c_str());
  763
+        continue;
  764
+      }
  765
+      if(extDemuxer)
  766
+      {
  767
+        //filter strange external audio files
  768
+        if(extDemuxer->GetNrOfStreams() > 1 || extDemuxer->GetStream(0)->type != STREAM_AUDIO)
  769
+        {
  770
+          iter = m_extInputStreams.erase(iter);
  771
+          SAFE_DELETE(extInput);
  772
+          delete extDemuxer;
  773
+          continue;
  774
+        }
  775
+
  776
+        m_SelectionStreams.UpdateExtAudio(extInput,extDemuxer);
  777
+
  778
+        int64_t len = extInput->GetLength();
  779
+        int64_t tim = extDemuxer->GetStreamLength();
  780
+        extInput->SetReadRate(len * 1000 / tim);
  781
+        m_extDemuxer.push_back(extDemuxer);
  782
+      }
  783
+      ++iter;
  784
+    }
  785
+    else
  786
+    {
  787
+      iter = m_extInputStreams.erase(iter);
  788
+      SAFE_DELETE(extInput);
  789
+    }
  790
+  }
  791
+  if(m_extDemuxer.size() == 0)
  792
+    return false;
  793
+  else
  794
+    return true;
  795
+}
  796
+
635 797
 bool CDVDPlayer::OpenDemuxStream()
636 798
 {
637 799
   if(m_pDemuxer)
@@ -747,7 +909,39 @@ void CDVDPlayer::OpenDefaultStreams(bool reset)
747 909
     CloseTeletextStream(true);
748 910
 }
749 911
 
750  
-bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
  912
+bool CDVDPlayer::ReadExternalAudioPacket(DemuxPacket*& packet, CDemuxStream*& stream)
  913
+{
  914
+  if(m_extAudio && m_extDemuxer[m_extAudioId])
  915
+    packet = m_extDemuxer[m_extAudioId]->Read();
  916
+
  917
+  if(packet)
  918
+  {
  919
+    UpdateCorrection(packet, m_offset_pts);
  920
+    if(packet->iStreamId < 0)
  921
+      return true;
  922
+
  923
+    stream =  m_extDemuxer[m_extAudioId]->GetStream(packet->iStreamId);
  924
+    if (!stream)
  925
+    {
  926
+      CLog::Log(LOGERROR, "%s - Error demux packet doesn't belong to a valid stream", __FUNCTION__);
  927
+      return false;
  928
+    }
  929
+    if(stream->source == STREAM_SOURCE_NONE)
  930
+    {
  931
+      /*I'm not sure what to do here, any ideas?
  932
+      Maybe replace the corresponding SelectionStream?
  933
+      */
  934
+
  935
+      //m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
  936
+      //m_SelectionStreams.m_Streams.erase(m_SelectionStreams.m_Streams.begin() + (m_CurrentAudio.id));
  937
+      //m_SelectionStreams.UpdateExtAudio(m_extInputStreams[streamId], m_extDemuxer[streamId]);
  938
+    }
  939
+    return true;
  940
+  }
  941
+  return false;
  942
+}
  943
+
  944
+bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream, bool onlyVideo)
751 945
 {
752 946
 
753 947
   // check if we should read from subtitle demuxer
@@ -781,6 +975,28 @@ bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
781 975
   if(m_pDemuxer)
782 976
     packet = m_pDemuxer->Read();
783 977
 
  978
+
  979
+  if(onlyVideo)
  980
+  {
  981
+    StreamType st;
  982
+    CDemuxStream* s;
  983
+    if (packet)
  984
+    {
  985
+      s = m_pDemuxer->GetStream(packet->iStreamId);
  986
+      st = s->type;
  987
+      while (st == STREAM_AUDIO && m_extAudio && packet)
  988
+      {
  989
+        packet = m_pDemuxer->Read();
  990
+        if (packet)
  991
+        {
  992
+          s = m_pDemuxer->GetStream(packet->iStreamId);
  993
+          st = s->type;
  994
+        }
  995
+        else break;
  996
+      }
  997
+    }
  998
+  }
  999
+
784 1000
   if(packet)
785 1001
   {
786 1002
     // stream changed, update and open defaults
@@ -840,7 +1056,11 @@ bool CDVDPlayer::IsValidStream(CCurrentStream& stream)
840 1056
   }
841 1057
   if(source == STREAM_SOURCE_DEMUX)
842 1058
   {
843  
-    CDemuxStream* st = m_pDemuxer->GetStream(stream.id);
  1059
+    CDemuxStream* st;
  1060
+    if(m_extAudio && stream.type == STREAM_AUDIO)
  1061
+      st = m_extDemuxer[m_extAudioId]->GetStream(0);
  1062
+    else
  1063
+      st = m_pDemuxer->GetStream(stream.id);
844 1064
     if(st == NULL || st->disabled)
845 1065
       return false;
846 1066
     if(st->type != stream.type)
@@ -918,6 +1138,8 @@ void CDVDPlayer::Process()
918 1138
     return;
919 1139
   }
920 1140
 
  1141
+  OpenExternalAudioInputStreams();
  1142
+
921 1143
   if(m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
922 1144
   {
923 1145
     CLog::Log(LOGNOTICE, "DVDPlayer: playing a dvd with menu's");
@@ -938,6 +1160,9 @@ void CDVDPlayer::Process()
938 1160
     return;
939 1161
   }
940 1162
 
  1163
+  if (!m_extInputStreams.empty())
  1164
+    OpenExternalAudioDemuxStreams();
  1165
+
941 1166
   // allow renderer to switch to fullscreen if requested
942 1167
   m_dvdPlayerVideo.EnableFullscreen(m_PlayerOptions.fullscreen);
943 1168
 
@@ -1007,7 +1232,15 @@ void CDVDPlayer::Process()
1007 1232
       else
1008 1233
         CLog::Log(LOGDEBUG, "%s - failed to start subtitle demuxing from: %d", __FUNCTION__, starttime);
1009 1234
     }
1010  
-  }
  1235
+
  1236
+    if (m_extAudio && m_extDemuxer[m_extAudioId])
  1237
+      {
  1238
+        if(m_extDemuxer[m_extAudioId]->SeekTime(starttime, false, &startpts))
  1239
+          CLog::Log(LOGDEBUG, "%s - starting external audio file demuxer from: %d", __FUNCTION__, starttime);
  1240
+        else
  1241
+          CLog::Log(LOGDEBUG, "%s - failed to start external audio file demuxing from: %d", __FUNCTION__, starttime);
  1242
+      }
  1243
+    }
1011 1244
 
1012 1245
   // make sure all selected stream have data on startup
1013 1246
   if (CachePVRStream())
@@ -1042,6 +1275,7 @@ void CDVDPlayer::Process()
1042 1275
         m_bAbortRequest = true;
1043 1276
         break;
1044 1277
       }
  1278
+      OpenExternalAudioInputStreams();
1045 1279
     }
1046 1280
 
1047 1281
     // should we open a new demuxer?
@@ -1059,6 +1293,8 @@ void CDVDPlayer::Process()
1059 1293
         break;
1060 1294
       }
1061 1295
 
  1296
+      if (!m_extInputStreams.empty())
  1297
+        OpenExternalAudioDemuxStreams();
1062 1298
       OpenDefaultStreams();
1063 1299
 
1064 1300
       if (CachePVRStream())
@@ -1095,7 +1331,16 @@ void CDVDPlayer::Process()
1095 1331
 
1096 1332
     DemuxPacket* pPacket = NULL;
1097 1333
     CDemuxStream *pStream = NULL;
1098  
-    ReadPacket(pPacket, pStream);
  1334
+
  1335
+    if (m_CurrentAudio.id != -1 && m_extAudio)
  1336
+      {
  1337
+        if(m_dvdPlayerAudio.GetLevel() < rate)
  1338
+          ReadExternalAudioPacket(pPacket, pStream);
  1339
+        else
  1340
+          ReadPacket(pPacket, pStream, true);
  1341
+    }
  1342
+    else
  1343
+      ReadPacket(pPacket, pStream, false);
1099 1344
     if (pPacket && !pStream)
1100 1345
     {
1101 1346
       /* probably a empty packet, just free it and move on */
@@ -1136,6 +1381,12 @@ void CDVDPlayer::Process()
1136 1381
       if(next == CDVDInputStream::NEXTSTREAM_OPEN)
1137 1382
       {
1138 1383
         SAFE_DELETE(m_pDemuxer);
  1384
+        for(unsigned int i = 0; i < m_extDemuxer.size(); i++)
  1385
+        {
  1386
+          if(m_extDemuxer[i])
  1387
+            SAFE_DELETE(m_extDemuxer[i]);
  1388
+        }
  1389
+
1139 1390
         m_CurrentAudio.stream = NULL;
1140 1391
         m_CurrentVideo.stream = NULL;
1141 1392
         m_CurrentSubtitle.stream = NULL;
@@ -1240,7 +1491,8 @@ void CDVDPlayer::ProcessPacket(CDemuxStream* pStream, DemuxPacket* pPacket)
1240 1491
 
1241 1492
     try
1242 1493
     {
1243  
-      if (pPacket->iStreamId == m_CurrentAudio.id && pStream->source == m_CurrentAudio.source && pStream->type == STREAM_AUDIO)
  1494
+      if (pPacket->iStreamId == m_CurrentAudio.id && pStream->source == m_CurrentAudio.source && pStream->type == STREAM_AUDIO
  1495
+        || m_extAudio && pStream->source == m_CurrentAudio.source && pStream->type == STREAM_AUDIO)
1244 1496
         ProcessAudioData(pStream, pPacket);
1245 1497
       else if (pPacket->iStreamId == m_CurrentVideo.id && pStream->source == m_CurrentVideo.source && pStream->type == STREAM_VIDEO)
1246 1498
         ProcessVideoData(pStream, pPacket);
@@ -1951,6 +2203,16 @@ void CDVDPlayer::OnExit()
1951 2203
     }
1952 2204
     m_pDemuxer = NULL;
1953 2205
 
  2206
+    for (unsigned int i = 0; i < m_extDemuxer.size(); i++)
  2207
+    {
  2208
+      if(m_extDemuxer[i])
  2209
+      {
  2210
+        CLog::Log(LOGNOTICE, "CDVDPlayer::OnExit() deleting external demuxer");
  2211
+        delete m_extDemuxer[i];
  2212
+      }
  2213
+    }
  2214
+    m_extDemuxer.clear();
  2215
+
1954 2216
     if (m_pSubtitleDemuxer)
1955 2217
     {
1956 2218
       CLog::Log(LOGNOTICE, "CDVDPlayer::OnExit() deleting subtitle demuxer");
@@ -1966,6 +2228,16 @@ void CDVDPlayer::OnExit()
1966 2228
     }
1967 2229
     m_pInputStream = NULL;
1968 2230
 
  2231
+    for(unsigned int i = 0; i < m_extInputStreams.size(); i++)
  2232
+    {
  2233
+      if(m_extInputStreams[i])
  2234
+      {
  2235
+        CLog::Log(LOGNOTICE, "CDVDPlayer::OnExit() deleting external input stream");
  2236
+        delete m_extInputStreams[i];
  2237
+      }
  2238
+    }
  2239
+    m_extInputStreams.clear();
  2240
+
1969 2241
     // clean up all selection streams
1970 2242
     m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_NONE);
1971 2243
 
@@ -1977,6 +2249,8 @@ void CDVDPlayer::OnExit()
1977 2249
     CLog::Log(LOGERROR, "%s - Exception thrown when trying to close down player, memory leak will follow", __FUNCTION__);
1978 2250
     m_pInputStream = NULL;
1979 2251
     m_pDemuxer = NULL;
  2252
+    m_extInputStreams.clear();
  2253
+    m_extDemuxer.clear();
1980 2254
   }
1981 2255
 
1982 2256
   m_bStop = true;
@@ -2038,6 +2312,15 @@ void CDVDPlayer::HandleMessages()
2038 2312
             if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward()))
2039 2313
               CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time);
2040 2314
           }
  2315
+
  2316
+          if (m_extAudio && m_extDemuxer[m_extAudioId])
  2317
+            {
  2318
+              if(!m_extDemuxer[m_extAudioId]->SeekTime(time, msg.GetBackward(), &start))
  2319
+                CLog::Log(LOGDEBUG, "failed to seek external audio demuxer: %d, success", time);
  2320
+              else
  2321
+                CLog::Log(LOGDEBUG, "external audio demuxer seek to: %d, success", time);
  2322
+            }
  2323
+
2041 2324
           FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate());
2042 2325
         }
2043 2326
         else
@@ -2063,6 +2346,12 @@ void CDVDPlayer::HandleMessages()
2063 2346
         // This should always be the case.
2064 2347
         if(m_pDemuxer && m_pDemuxer->SeekChapter(msg.GetChapter(), &start))
2065 2348
         {
  2349
+          if (m_extAudio && m_extDemuxer[m_extAudioId])
  2350
+          {
  2351
+            if(!m_extDemuxer[m_extAudioId]->SeekTime(DVD_TIME_TO_MSEC(start)))
  2352
+              CLog::Log(LOGDEBUG, "failed to seek to chapter %d on external audio demuxer, time: %d", msg.GetChapter(), DVD_TIME_TO_MSEC(start));
  2353
+          }
  2354
+
2066 2355
           FlushBuffers(false, start, true);
2067 2356
           m_callback.OnPlayBackSeekChapter(msg.GetChapter());
2068 2357
         }
@@ -2080,6 +2369,11 @@ void CDVDPlayer::HandleMessages()
2080 2369
             m_pDemuxer->Reset();
2081 2370
           if(m_pSubtitleDemuxer)
2082 2371
             m_pSubtitleDemuxer->Reset();
  2372
+          for(unsigned int i = 0; i < m_extDemuxer.size(); i++)
  2373
+          {
  2374
+            if(m_extDemuxer[i])
  2375
+              m_extDemuxer[i]->Reset();
  2376
+          }
2083 2377
       }
2084 2378
       else if (pMsg->IsType(CDVDMsg::PLAYER_SET_AUDIOSTREAM))
2085 2379
       {
@@ -2207,6 +2501,9 @@ void CDVDPlayer::HandleMessages()
2207 2501
         //        until our buffers are somewhat filled
2208 2502
         if(m_pDemuxer)
2209 2503
           m_pDemuxer->SetSpeed(speed);
  2504
+
  2505
+        if (m_extAudio && m_extDemuxer[m_extAudioId])
  2506
+            m_extDemuxer[m_extAudioId]->SetSpeed(speed);
2210 2507
       }
2211 2508
       else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) && m_messenger.GetPacketCount(CDVDMsg::PLAYER_CHANNEL_SELECT_NUMBER) == 0)
2212 2509
       {
@@ -2815,10 +3112,27 @@ bool CDVDPlayer::OpenAudioStream(int iStream, int source, bool reset)
2815 3112
   if (!m_pDemuxer)
2816 3113
     return false;
2817 3114
 
2818  
-  CDemuxStream* pStream = m_pDemuxer->GetStream(iStream);
  3115
+  CDemuxStream* pStream;
  3116
+
  3117
+  if(iStream >= m_extAudioOffset && iStream < ((int) (m_extAudioOffset + m_extDemuxer.size())))
  3118
+  {
  3119
+    m_extAudio = true;
  3120
+    m_extAudioId = iStream - m_extAudioOffset;
  3121
+  }
  3122
+  else
  3123
+    m_extAudio = false;
  3124
+
  3125
+  if(m_extAudio)
  3126
+  {
  3127
+    // Stream 0, so no fancy ext audio files with more than one stream
  3128
+    // we already filterd out these files
  3129
+    pStream = m_extDemuxer[m_extAudioId]->GetStream(0);
  3130
+
2819 3131
   if (!pStream || pStream->disabled)
2820 3132
     return false;
2821  
-
  3133
+  }
  3134
+  else
  3135
+    pStream = m_pDemuxer->GetStream(iStream);
2822 3136
   if( m_CurrentAudio.id < 0 &&  m_CurrentVideo.id >= 0 )
2823 3137
   {
2824 3138
     // up until now we wheren't playing audio, but we did play video
@@ -3911,12 +4225,18 @@ void CDVDPlayer::UpdatePlayState(double timeout)
3911 4225
   else
3912 4226
     state.time_offset = DVD_MSEC_TO_TIME(state.time) - state.dts;
3913 4227
 
3914  
-  if (m_CurrentAudio.id >= 0 && m_pDemuxer)
  4228
+  if (m_CurrentAudio.id >= 0 && m_pDemuxer && !m_extAudio)
3915 4229
   {
3916 4230
     CDemuxStream* pStream = m_pDemuxer->GetStream(m_CurrentAudio.id);
3917 4231
     if (pStream && pStream->type == STREAM_AUDIO)
3918 4232
       ((CDemuxStreamAudio*)pStream)->GetStreamInfo(state.demux_audio);
3919 4233
   }
  4234
+  else if (m_extAudio && m_extDemuxer[m_extAudioId])
  4235
+  {
  4236
+    CDemuxStream* pStream = m_extDemuxer[m_extAudioId]->GetStream(0);
  4237
+    if (pStream && pStream->type == STREAM_AUDIO)
  4238
+      ((CDemuxStreamAudio*)pStream)->GetStreamInfo(state.demux_audio);
  4239
+  }
3920 4240
   else
3921 4241
     state.demux_audio = "";
3922 4242
 
@@ -4003,11 +4323,17 @@ bool CDVDPlayer::Record(bool bOnOff)
4003 4323
 
4004 4324
 int CDVDPlayer::GetChannels()
4005 4325
 {
4006  
-  if (m_pDemuxer && (m_CurrentAudio.id != -1))
  4326
+  if (m_pDemuxer && (m_CurrentAudio.id != -1) && !m_extAudio)
4007 4327
   {
4008 4328
     CDemuxStreamAudio* stream = static_cast<CDemuxStreamAudio*>(m_pDemuxer->GetStream(m_CurrentAudio.id));
4009 4329
     if (stream)
4010 4330
       return stream->iChannels;
  4331
+  } 
  4332
+  else if (m_extAudio && m_extDemuxer[m_extAudioId])
  4333
+  {
  4334
+    CDemuxStreamAudio* stream = static_cast<CDemuxStreamAudio*>(m_extDemuxer[m_extAudioId]->GetStream(0));
  4335
+    if (stream)
  4336
+      return stream->iChannels;
4011 4337
   }
4012 4338
   return -1;
4013 4339
 }
@@ -4015,8 +4341,11 @@ int CDVDPlayer::GetChannels()
4015 4341
 CStdString CDVDPlayer::GetAudioCodecName()
4016 4342
 {
4017 4343
   CStdString retVal;
4018  
-  if (m_pDemuxer && (m_CurrentAudio.id != -1))
  4344
+  if (m_pDemuxer && (m_CurrentAudio.id != -1) && ! m_extAudio)
4019 4345
     m_pDemuxer->GetStreamCodecName(m_CurrentAudio.id, retVal);
  4346
+  else if (m_extAudio && m_extDemuxer[m_extAudioId])
  4347
+    m_extDemuxer[m_extAudioId]->GetStreamCodecName(0, retVal);
  4348
+
4020 4349
   return retVal;
4021 4350
 }
4022 4351
 
@@ -4054,7 +4383,7 @@ bool CDVDPlayer::GetStreamDetails(CStreamDetails &details)
4054 4383
 {
4055 4384
   if (m_pDemuxer)
4056 4385
   {
4057  
-    bool result=CDVDFileInfo::DemuxerToStreamDetails(m_pInputStream, m_pDemuxer, details);
  4386
+    bool result=CDVDFileInfo::DemuxerToStreamDetails(m_pInputStream, m_pDemuxer, m_extDemuxer, details);
4058 4387
     if (result && details.GetStreamCount(CStreamDetail::VIDEO) > 0) // this is more correct (dvds in particular)
4059 4388
     {
4060 4389
       GetVideoAspectRatio(((CStreamDetailVideo*)details.GetNthStream(CStreamDetail::VIDEO,0))->m_fAspect);
11  xbmc/cores/dvdplayer/DVDPlayer.h
@@ -157,6 +157,7 @@ class CSelectionStreams
157 157
 
158 158
   void             Update  (SelectionStream& s);
159 159
   void             Update  (CDVDInputStream* input, CDVDDemux* demuxer);
  160
+  void             UpdateExtAudio  (CDVDInputStream* input, CDVDDemux* ext_demuxer);
160 161
 };
161 162
 
162 163
 
@@ -329,14 +330,17 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
329 330
   void UpdateTimestamps(CCurrentStream& current, DemuxPacket* pPacket);
330 331
   void SendPlayerMessage(CDVDMsg* pMsg, unsigned int target);
331 332
 
332  
-  bool ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream);
  333
+  bool ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream, bool onlyVideo);
  334
+  bool ReadExternalAudioPacket(DemuxPacket*& packet, CDemuxStream*& stream);
333 335
   bool IsValidStream(CCurrentStream& stream);
334 336
   bool IsBetterStream(CCurrentStream& current, CDemuxStream* stream);
335 337
   bool CheckDelayedChannelEntry(void);
336 338
 
337 339
   bool OpenInputStream();
  340
+  bool OpenExternalAudioInputStreams();
338 341
   bool OpenDemuxStream();
339 342
   void OpenDefaultStreams(bool reset = true);
  343
+  bool OpenExternalAudioDemuxStreams();
340 344
 
341 345
   void UpdateApplication(double timeout);
342 346
   void UpdatePlayState(double timeout);
@@ -383,6 +387,11 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
383 387
   CDVDDemux* m_pSubtitleDemuxer;
384 388
 
385 389
   CStdString m_lastSub;
  390
+  std::vector<CDVDInputStream*> m_extInputStreams;
  391
+  std::vector<CDVDDemux*> m_extDemuxer;
  392
+  bool m_extAudio;
  393
+  int m_extAudioOffset;
  394
+  int m_extAudioId;
386 395
 
387 396
   struct SDVDInfo
388 397
   {
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.