static int dvd_file_read(URLContext *h, BYTE* buf, int size) { //if (g_urltimeout && GetTickCount() > g_urltimeout) // return -1; CDVDInputStream* pInputStream = (CDVDInputStream*)h->priv_data; return pInputStream->Read(buf, size); }
/* static int dvd_file_write(URLContext *h, BYTE* buf, int size) { return -1; } */ static offset_t dvd_file_seek(URLContext *h, offset_t pos, int whence) { //if (g_urltimeout && GetTickCount() > g_urltimeout) // return -1; CDVDInputStream* pInputStream = (CDVDInputStream*)h->priv_data; if(whence == AVSEEK_SIZE) return pInputStream->GetLength(); else return pInputStream->Seek(pos, whence); }
/** * \brief Open the item pointed to by pItem and extact streamdetails * \return true if the stream details have changed */ bool CDVDFileInfo::GetFileStreamDetails(CFileItem *pItem) { if (!pItem) return false; std::string strFileNameAndPath; if (pItem->HasVideoInfoTag()) strFileNameAndPath = pItem->GetVideoInfoTag()->m_strFileNameAndPath; if (strFileNameAndPath.empty()) strFileNameAndPath = pItem->GetPath(); std::string playablePath = strFileNameAndPath; if (URIUtils::IsStack(playablePath)) playablePath = XFILE::CStackDirectory::GetFirstStackedFile(playablePath); CFileItem item(playablePath, false); item.SetMimeTypeForInternetFile(); CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, item); if (!pInputStream) return false; if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { delete pInputStream; return false; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) || !pInputStream->Open()) { delete pInputStream; return false; } CDVDDemux *pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream, true); if (pDemuxer) { bool retVal = DemuxerToStreamDetails(pInputStream, pDemuxer, pItem->GetVideoInfoTag()->m_streamDetails, strFileNameAndPath); delete pDemuxer; delete pInputStream; return retVal; } else { delete pInputStream; return false; } }
/** * \brief Open the item pointed to by pItem and extact streamdetails * \return true if the stream details have changed */ bool CDVDFileInfo::GetFileStreamDetails(CFileItem *pItem) { if (!pItem) return false; CStdString strFileNameAndPath; if (pItem->HasVideoInfoTag()) strFileNameAndPath = pItem->GetVideoInfoTag()->m_strFileNameAndPath; else return false; CStdString playablePath = strFileNameAndPath; if (URIUtils::IsStack(playablePath)) playablePath = XFILE::CStackDirectory::GetFirstStackedFile(playablePath); CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, playablePath, ""); if (!pInputStream) return false; if (pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) || !pInputStream->Open(playablePath.c_str(), "")) { delete pInputStream; return false; } CDVDDemux *pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream); if (pDemuxer) { bool retVal = DemuxerToStreamDetails(pInputStream, pDemuxer, pItem->GetVideoInfoTag()->m_streamDetails, strFileNameAndPath); delete pDemuxer; delete pInputStream; return retVal; } else { delete pInputStream; return false; } }
bool CDVDFileInfo::ExtractThumb(const std::string &strPath, CTextureDetails &details, CStreamDetails *pStreamDetails, int pos) { std::string redactPath = CURL::GetRedacted(strPath); unsigned int nTime = XbmcThreads::SystemClockMillis(); CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strPath, ""); if (!pInputStream) { CLog::Log(LOGERROR, "InputStream: Error creating stream for %s", redactPath.c_str()); return false; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) || pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY)) { CLog::Log(LOGDEBUG, "%s: disc streams not supported for thumb extraction, file: %s", __FUNCTION__, redactPath.c_str()); delete pInputStream; return false; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { SAFE_DELETE(pInputStream); return false; } if (!pInputStream->Open(strPath.c_str(), "", true)) { CLog::Log(LOGERROR, "InputStream: Error opening, %s", redactPath.c_str()); if (pInputStream) SAFE_DELETE(pInputStream); return false; } CDVDDemux *pDemuxer = NULL; try { pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream, true); if(!pDemuxer) { SAFE_DELETE(pInputStream); CLog::Log(LOGERROR, "%s - Error creating demuxer", __FUNCTION__); return false; } } catch(...) { CLog::Log(LOGERROR, "%s - Exception thrown when opening demuxer", __FUNCTION__); if (pDemuxer) SAFE_DELETE(pDemuxer); SAFE_DELETE(pInputStream); return false; } if (pStreamDetails) { DemuxerToStreamDetails(pInputStream, pDemuxer, *pStreamDetails, strPath); //extern subtitles std::vector<std::string> filenames; std::string video_path; if (strPath.empty()) video_path = pInputStream->GetFileName(); else video_path = strPath; CUtil::ScanForExternalSubtitles(video_path, filenames); for(unsigned int i=0;i<filenames.size();i++) { // if vobsub subtitle: if (URIUtils::GetExtension(filenames[i]) == ".idx") { std::string strSubFile; if ( CUtil::FindVobSubPair(filenames, filenames[i], strSubFile) ) AddExternalSubtitleToDetails(video_path, *pStreamDetails, filenames[i], strSubFile); } else { if ( !CUtil::IsVobSub(filenames, filenames[i]) ) { AddExternalSubtitleToDetails(video_path, *pStreamDetails, filenames[i]); } } } } int nVideoStream = -1; for (int i = 0; i < pDemuxer->GetNrOfStreams(); i++) { CDemuxStream* pStream = pDemuxer->GetStream(i); if (pStream) { // ignore if it's a picture attachment (e.g. jpeg artwork) if(pStream->type == STREAM_VIDEO && !(pStream->flags & AV_DISPOSITION_ATTACHED_PIC)) nVideoStream = i; else pStream->SetDiscard(AVDISCARD_ALL); } } bool bOk = false; int packetsTried = 0; if (nVideoStream != -1) { CDVDVideoCodec *pVideoCodec; CDVDStreamInfo hint(*pDemuxer->GetStream(nVideoStream), true); hint.software = true; if (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO) { // libmpeg2 is not thread safe so use ffmepg for mpeg2/mpeg1 thumb extraction CDVDCodecOptions dvdOptions; pVideoCodec = CDVDFactoryCodec::OpenCodec(new CDVDVideoCodecFFmpeg(), hint, dvdOptions); } else { pVideoCodec = CDVDFactoryCodec::CreateVideoCodec( hint ); } if (pVideoCodec) { int nTotalLen = pDemuxer->GetStreamLength(); int nSeekTo = (pos==-1?nTotalLen / 3:pos); CLog::Log(LOGDEBUG,"%s - seeking to pos %dms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, redactPath.c_str()); if (pDemuxer->SeekTime(nSeekTo, true)) { int iDecoderState = VC_ERROR; DVDVideoPicture picture; memset(&picture, 0, sizeof(picture)); // num streams * 160 frames, should get a valid frame, if not abort. int abort_index = pDemuxer->GetNrOfStreams() * 160; do { DemuxPacket* pPacket = pDemuxer->Read(); packetsTried++; if (!pPacket) break; if (pPacket->iStreamId != nVideoStream) { CDVDDemuxUtils::FreeDemuxPacket(pPacket); continue; } iDecoderState = pVideoCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); CDVDDemuxUtils::FreeDemuxPacket(pPacket); if (iDecoderState & VC_ERROR) break; if (iDecoderState & VC_PICTURE) { memset(&picture, 0, sizeof(DVDVideoPicture)); if (pVideoCodec->GetPicture(&picture)) { if(!(picture.iFlags & DVP_FLAG_DROPPED)) break; } } } while (abort_index--); if (iDecoderState & VC_PICTURE && !(picture.iFlags & DVP_FLAG_DROPPED)) { { unsigned int nWidth = g_advancedSettings.GetThumbSize(); double aspect = (double)picture.iDisplayWidth / (double)picture.iDisplayHeight; if(hint.forced_aspect && hint.aspect != 0) aspect = hint.aspect; unsigned int nHeight = (unsigned int)((double)g_advancedSettings.GetThumbSize() / aspect); uint8_t *pOutBuf = new uint8_t[nWidth * nHeight * 4]; struct SwsContext *context = sws_getContext(picture.iWidth, picture.iHeight, PIX_FMT_YUV420P, nWidth, nHeight, PIX_FMT_BGRA, SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL); if (context) { uint8_t *src[] = { picture.data[0], picture.data[1], picture.data[2], 0 }; int srcStride[] = { picture.iLineSize[0], picture.iLineSize[1], picture.iLineSize[2], 0 }; uint8_t *dst[] = { pOutBuf, 0, 0, 0 }; int dstStride[] = { (int)nWidth*4, 0, 0, 0 }; int orientation = DegreeToOrientation(hint.orientation); sws_scale(context, src, srcStride, 0, picture.iHeight, dst, dstStride); sws_freeContext(context); details.width = nWidth; details.height = nHeight; CPicture::CacheTexture(pOutBuf, nWidth, nHeight, nWidth * 4, orientation, nWidth, nHeight, CTextureCache::GetCachedPath(details.file)); bOk = true; } SAFE_DELETE_ARRAY(pOutBuf); } } else { CLog::Log(LOGDEBUG,"%s - decode failed in %s after %d packets.", __FUNCTION__, redactPath.c_str(), packetsTried); } } SAFE_DELETE(pVideoCodec); } } if (pDemuxer) SAFE_DELETE(pDemuxer); SAFE_DELETE(pInputStream); if(!bOk) { XFILE::CFile file; if(file.OpenForWrite(CTextureCache::GetCachedPath(details.file))) file.Close(); } unsigned int nTotalTime = XbmcThreads::SystemClockMillis() - nTime; CLog::Log(LOGDEBUG,"%s - measured %u ms to extract thumb from file <%s> in %d packets. ", __FUNCTION__, nTotalTime, redactPath.c_str(), packetsTried); return bOk; }
bool CDVDSubtitleStream::Open(const string& strFile) { CDVDInputStream* pInputStream; pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strFile, ""); if (pInputStream && pInputStream->Open(strFile.c_str(), "")) { unsigned char buffer[16384]; int size_read = 0; size_read = pInputStream->Read(buffer,3); bool isUTF8 = false; bool isUTF16 = false; if (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF) isUTF8 = true; else if (buffer[0] == 0xFF && buffer[1] == 0xFE) { isUTF16 = true; pInputStream->Seek(2, SEEK_SET); } else pInputStream->Seek(0, SEEK_SET); if (isUTF16) { std::wstringstream wstringstream; while( (size_read = pInputStream->Read(buffer, sizeof(buffer)-2) ) > 0 ) { buffer[size_read] = buffer[size_read + 1] = '\0'; CStdStringW temp; g_charsetConverter.utf16LEtoW(std::u16string((char16_t*)buffer),temp); wstringstream << temp; } delete pInputStream; CStdString strUTF8; g_charsetConverter.wToUTF8(CStdStringW(wstringstream.str()),strUTF8); m_stringstream.str(""); m_stringstream << strUTF8; } else { while( (size_read = pInputStream->Read(buffer, sizeof(buffer)-1) ) > 0 ) { buffer[size_read] = '\0'; m_stringstream << buffer; } delete pInputStream; if (!isUTF8) isUTF8 = CUtf8Utils::isValidUtf8(m_stringstream.str()); if (!isUTF8) { CStdStringW strUTF16; CStdString strUTF8; g_charsetConverter.subtitleCharsetToW(m_stringstream.str(), strUTF16); g_charsetConverter.wToUTF8(strUTF16,strUTF8); m_stringstream.str(""); m_stringstream << strUTF8; } } return true; } delete pInputStream; return false; }
bool CDVDFileInfo::ExtractThumb(const std::string &strPath, CTextureDetails &details, CStreamDetails *pStreamDetails, int pos) { std::string redactPath = CURL::GetRedacted(strPath); unsigned int nTime = XbmcThreads::SystemClockMillis(); CFileItem item(strPath, false); item.SetMimeTypeForInternetFile(); CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, item); if (!pInputStream) { CLog::Log(LOGERROR, "InputStream: Error creating stream for %s", redactPath.c_str()); return false; } if (!pInputStream->Open()) { CLog::Log(LOGERROR, "InputStream: Error opening, %s", redactPath.c_str()); if (pInputStream) delete pInputStream; return false; } CDVDDemux *pDemuxer = NULL; try { pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream, true); if(!pDemuxer) { delete pInputStream; CLog::Log(LOGERROR, "%s - Error creating demuxer", __FUNCTION__); return false; } } catch(...) { CLog::Log(LOGERROR, "%s - Exception thrown when opening demuxer", __FUNCTION__); if (pDemuxer) delete pDemuxer; delete pInputStream; return false; } if (pStreamDetails) { DemuxerToStreamDetails(pInputStream, pDemuxer, *pStreamDetails, strPath); //extern subtitles std::vector<std::string> filenames; std::string video_path; if (strPath.empty()) video_path = pInputStream->GetFileName(); else video_path = strPath; CUtil::ScanForExternalSubtitles(video_path, filenames); for(unsigned int i=0;i<filenames.size();i++) { // if vobsub subtitle: if (URIUtils::GetExtension(filenames[i]) == ".idx") { std::string strSubFile; if ( CUtil::FindVobSubPair(filenames, filenames[i], strSubFile) ) AddExternalSubtitleToDetails(video_path, *pStreamDetails, filenames[i], strSubFile); } else { if ( !CUtil::IsVobSub(filenames, filenames[i]) ) { AddExternalSubtitleToDetails(video_path, *pStreamDetails, filenames[i]); } } } } int nVideoStream = -1; int64_t demuxerId = -1; for (CDemuxStream* pStream : pDemuxer->GetStreams()) { if (pStream) { // ignore if it's a picture attachment (e.g. jpeg artwork) if (pStream->type == STREAM_VIDEO && !(pStream->flags & AV_DISPOSITION_ATTACHED_PIC)) { nVideoStream = pStream->uniqueId; demuxerId = pStream->demuxerId; } else pDemuxer->EnableStream(pStream->demuxerId, pStream->uniqueId, false); } } bool bOk = false; int packetsTried = 0; if (nVideoStream != -1) { CDVDVideoCodec *pVideoCodec; std::unique_ptr<CProcessInfo> pProcessInfo(CProcessInfo::CreateInstance()); CDVDStreamInfo hint(*pDemuxer->GetStream(demuxerId, nVideoStream), true); hint.software = true; pVideoCodec = CDVDFactoryCodec::CreateVideoCodec(hint, *pProcessInfo); if (pVideoCodec) { int nTotalLen = pDemuxer->GetStreamLength(); int nSeekTo = (pos==-1) ? nTotalLen / 3 : pos; CLog::Log(LOGDEBUG,"%s - seeking to pos %dms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, redactPath.c_str()); if (pDemuxer->SeekTime(nSeekTo, true)) { int iDecoderState = VC_ERROR; DVDVideoPicture picture; memset(&picture, 0, sizeof(picture)); // num streams * 160 frames, should get a valid frame, if not abort. int abort_index = pDemuxer->GetNrOfStreams() * 160; do { DemuxPacket* pPacket = pDemuxer->Read(); packetsTried++; if (!pPacket) break; if (pPacket->iStreamId != nVideoStream) { CDVDDemuxUtils::FreeDemuxPacket(pPacket); continue; } iDecoderState = pVideoCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); CDVDDemuxUtils::FreeDemuxPacket(pPacket); if (iDecoderState & VC_ERROR) break; if (iDecoderState & VC_PICTURE) { memset(&picture, 0, sizeof(DVDVideoPicture)); if (pVideoCodec->GetPicture(&picture)) { if(!(picture.iFlags & DVP_FLAG_DROPPED)) break; } } } while (abort_index--); if (iDecoderState & VC_PICTURE && !(picture.iFlags & DVP_FLAG_DROPPED)) { { unsigned int nWidth = g_advancedSettings.m_imageRes; double aspect = (double)picture.iDisplayWidth / (double)picture.iDisplayHeight; if(hint.forced_aspect && hint.aspect != 0) aspect = hint.aspect; unsigned int nHeight = (unsigned int)((double)g_advancedSettings.m_imageRes / aspect); uint8_t *pOutBuf = (uint8_t*)av_malloc(nWidth * nHeight * 4); struct SwsContext *context = sws_getContext(picture.iWidth, picture.iHeight, AV_PIX_FMT_YUV420P, nWidth, nHeight, AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL); if (context) { uint8_t *src[] = { picture.data[0], picture.data[1], picture.data[2], 0 }; int srcStride[] = { picture.iLineSize[0], picture.iLineSize[1], picture.iLineSize[2], 0 }; uint8_t *dst[] = { pOutBuf, 0, 0, 0 }; int dstStride[] = { (int)nWidth*4, 0, 0, 0 }; int orientation = DegreeToOrientation(hint.orientation); sws_scale(context, src, srcStride, 0, picture.iHeight, dst, dstStride); sws_freeContext(context); details.width = nWidth; details.height = nHeight; CPicture::CacheTexture(pOutBuf, nWidth, nHeight, nWidth * 4, orientation, nWidth, nHeight, CTextureCache::GetCachedPath(details.file)); bOk = true; } av_free(pOutBuf); } } else { CLog::Log(LOGDEBUG,"%s - decode failed in %s after %d packets.", __FUNCTION__, redactPath.c_str(), packetsTried); } } delete pVideoCodec; } } if (pDemuxer) delete pDemuxer; delete pInputStream; if(!bOk) { XFILE::CFile file; if(file.OpenForWrite(CTextureCache::GetCachedPath(details.file))) file.Close(); } unsigned int nTotalTime = XbmcThreads::SystemClockMillis() - nTime; CLog::Log(LOGDEBUG,"%s - measured %u ms to extract thumb from file <%s> in %d packets. ", __FUNCTION__, nTotalTime, redactPath.c_str(), packetsTried); return bOk; }
CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream) { if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP)) { CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream; CHttpHeader *header = pHttpStream->GetHttpHeader(); /* check so we got the meta information as requested in our http header */ if( header->GetValue("icy-metaint").length() > 0 ) { auto_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } #ifdef HAS_FILESYSTEM_HTSP if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP)) { auto_ptr<CDVDDemuxHTSP> demuxer(new CDVDDemuxHTSP()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } #endif if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream; CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream(); if(pOtherStream) { /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pOtherStream)) return demuxer.release(); else return NULL; } } std::string filename = pInputStream->GetFileName(); /* Use PVR demuxer only for live streams */ if (filename.substr(0, 14) == "pvr://channels") { PVR_SERVERPROPS *pProps = g_PVRManager.GetCurrentClientProps(); if (pProps && pProps->HandleDemuxing) { auto_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } } auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; }
CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream, bool fileinfo) { if (!pInputStream) return NULL; // Try to open the AirTunes demuxer if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 ) { // audio/x-xbmc-pcm this is the used codec for AirTunes // (apples audio only streaming) unique_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP)) { CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream; CHttpHeader *header = pHttpStream->GetHttpHeader(); /* check so we got the meta information as requested in our http header */ if( header->GetValue("icy-metaint").length() > 0 ) { unique_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } bool streaminfo = true; /* Look for streams before playback */ if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream; CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream(); /* Don't parse the streaminfo for some cases of streams to reduce the channel switch time */ bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName()); streaminfo = !useFastswitch; if(pOtherStream) { /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pOtherStream, streaminfo)) return demuxer.release(); else return NULL; } } /* Use PVR demuxer only for live streams */ if (URIUtils::IsPVRChannel(pInputStream->GetFileName())) { std::shared_ptr<CPVRClient> client; if (g_PVRClients->GetPlayingClient(client) && client->HandlesDemuxing()) { unique_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName()); streaminfo = !useFastswitch; } unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pInputStream, streaminfo, fileinfo)) return demuxer.release(); else return NULL; }
CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream, bool fileinfo) { if (!pInputStream) return NULL; // Try to open the AirTunes demuxer if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 ) { // audio/x-xbmc-pcm this is the used codec for AirTunes // (apples audio only streaming) std::unique_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } // Try to open CDDA demuxer if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("application/octet-stream") == 0) { std::string filename = pInputStream->GetFileName(); if (filename.substr(0, 7) == "cdda://") { CLog::Log(LOGDEBUG, "DVDFactoryDemuxer: Stream is probably CD audio. Creating CDDA demuxer."); std::unique_ptr<CDVDDemuxCDDA> demuxer(new CDVDDemuxCDDA()); if (demuxer->Open(pInputStream)) { return demuxer.release(); } } } // Input stream handles demuxing if (pInputStream->GetIDemux()) { std::unique_ptr<CDVDDemuxClient> demuxer(new CDVDDemuxClient()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return nullptr; } bool streaminfo = true; /* Look for streams before playback */ if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream; CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream(); /* Don't parse the streaminfo for some cases of streams to reduce the channel switch time */ bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName()); streaminfo = !useFastswitch; if (pOtherStream) { /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { std::unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pOtherStream, streaminfo)) return demuxer.release(); else return nullptr; } } } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName()); streaminfo = !useFastswitch; } // Try to open the MultiFiles demuxer if (pInputStream->IsStreamType(DVDSTREAM_TYPE_MULTIFILES)) { std::unique_ptr<CDemuxMultiSource> demuxer(new CDemuxMultiSource()); if (demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } std::unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pInputStream, streaminfo, fileinfo)) return demuxer.release(); else return NULL; }
bool CDVDFileInfo::ExtractThumb(const CStdString &strPath, CTextureDetails &details, CStreamDetails *pStreamDetails) { unsigned int nTime = XbmcThreads::SystemClockMillis(); CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strPath, ""); if (!pInputStream) { CLog::Log(LOGERROR, "InputStream: Error creating stream for %s", strPath.c_str()); return false; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) { CLog::Log(LOGERROR, "InputStream: dvd streams not supported for thumb extraction, file: %s", strPath.c_str()); delete pInputStream; return false; } if (!pInputStream->Open(strPath.c_str(), "")) { CLog::Log(LOGERROR, "InputStream: Error opening, %s", strPath.c_str()); if (pInputStream) delete pInputStream; return false; } CDVDDemux *pDemuxer = NULL; try { pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream); if(!pDemuxer) { delete pInputStream; CLog::Log(LOGERROR, "%s - Error creating demuxer", __FUNCTION__); return false; } } catch(...) { CLog::Log(LOGERROR, "%s - Exception thrown when opening demuxer", __FUNCTION__); if (pDemuxer) delete pDemuxer; delete pInputStream; return false; } if (pStreamDetails) DemuxerToStreamDetails(pInputStream, pDemuxer, *pStreamDetails, strPath); CDemuxStream* pStream = NULL; int nVideoStream = -1; for (int i = 0; i < pDemuxer->GetNrOfStreams(); i++) { pStream = pDemuxer->GetStream(i); if (pStream) { if(pStream->type == STREAM_VIDEO) nVideoStream = i; else pStream->SetDiscard(AVDISCARD_ALL); } } bool bOk = false; int packetsTried = 0; if (nVideoStream != -1) { CDVDVideoCodec *pVideoCodec; CDVDStreamInfo hint(*pDemuxer->GetStream(nVideoStream), true); hint.software = true; if (hint.codec == CODEC_ID_MPEG2VIDEO || hint.codec == CODEC_ID_MPEG1VIDEO) { // libmpeg2 is not thread safe so use ffmepg for mpeg2/mpeg1 thumb extraction CDVDCodecOptions dvdOptions; pVideoCodec = CDVDFactoryCodec::OpenCodec(new CDVDVideoCodecFFmpeg(), hint, dvdOptions); } else { pVideoCodec = CDVDFactoryCodec::CreateVideoCodec( hint ); } if (pVideoCodec) { int nTotalLen = pDemuxer->GetStreamLength(); int nSeekTo = nTotalLen / 3; CLog::Log(LOGDEBUG,"%s - seeking to pos %dms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, strPath.c_str()); if (pDemuxer->SeekTime(nSeekTo, true)) { DemuxPacket* pPacket = NULL; int iDecoderState = VC_ERROR; DVDVideoPicture picture; memset(&picture, 0, sizeof(picture)); // num streams * 80 frames, should get a valid frame, if not abort. int abort_index = pDemuxer->GetNrOfStreams() * 80; do { pPacket = pDemuxer->Read(); packetsTried++; if (!pPacket) break; if (pPacket->iStreamId != nVideoStream) { CDVDDemuxUtils::FreeDemuxPacket(pPacket); continue; } iDecoderState = pVideoCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); CDVDDemuxUtils::FreeDemuxPacket(pPacket); if (iDecoderState & VC_ERROR) break; if (iDecoderState & VC_PICTURE) { memset(&picture, 0, sizeof(DVDVideoPicture)); if (pVideoCodec->GetPicture(&picture)) { if(!(picture.iFlags & DVP_FLAG_DROPPED)) break; } } } while (abort_index--); if (iDecoderState & VC_PICTURE && !(picture.iFlags & DVP_FLAG_DROPPED)) { { unsigned int nWidth = g_advancedSettings.GetThumbSize(); double aspect = (double)picture.iDisplayWidth / (double)picture.iDisplayHeight; if(hint.forced_aspect && hint.aspect != 0) aspect = hint.aspect; unsigned int nHeight = (unsigned int)((double)g_advancedSettings.GetThumbSize() / aspect); DllSwScale dllSwScale; dllSwScale.Load(); BYTE *pOutBuf = new BYTE[nWidth * nHeight * 4]; struct SwsContext *context = dllSwScale.sws_getContext(picture.iWidth, picture.iHeight, PIX_FMT_YUV420P, nWidth, nHeight, PIX_FMT_BGRA, SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL); uint8_t *src[] = { picture.data[0], picture.data[1], picture.data[2], 0 }; int srcStride[] = { picture.iLineSize[0], picture.iLineSize[1], picture.iLineSize[2], 0 }; uint8_t *dst[] = { pOutBuf, 0, 0, 0 }; int dstStride[] = { (int)nWidth*4, 0, 0, 0 }; if (context) { int orientation = DegreeToOrientation(hint.orientation); dllSwScale.sws_scale(context, src, srcStride, 0, picture.iHeight, dst, dstStride); dllSwScale.sws_freeContext(context); details.width = nWidth; details.height = nHeight; CPicture::CacheTexture(pOutBuf, nWidth, nHeight, nWidth * 4, orientation, nWidth, nHeight, CTextureCache::GetCachedPath(details.file)); bOk = true; } dllSwScale.Unload(); delete [] pOutBuf; } } else { CLog::Log(LOGDEBUG,"%s - decode failed in %s after %d packets.", __FUNCTION__, strPath.c_str(), packetsTried); } } delete pVideoCodec; } } if (pDemuxer) delete pDemuxer; delete pInputStream; if(!bOk) { XFILE::CFile file; if(file.OpenForWrite(CTextureCache::GetCachedPath(details.file))) file.Close(); } unsigned int nTotalTime = XbmcThreads::SystemClockMillis() - nTime; CLog::Log(LOGDEBUG,"%s - measured %u ms to extract thumb from file <%s> in %d packets. ", __FUNCTION__, nTotalTime, strPath.c_str(), packetsTried); return bOk; }
CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream) { // Try to open the AirTunes demuxer if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 ) { // audio/x-xbmc-pcm this is the used codec for AirTunes // (apples audio only streaming) auto_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_SPOTIFY)) { auto_ptr<CDVDDemuxSpotify> demuxer(new CDVDDemuxSpotify()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP)) { CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream; CHttpHeader *header = pHttpStream->GetHttpHeader(); /* check so we got the meta information as requested in our http header */ if( header->GetValue("icy-metaint").length() > 0 ) { auto_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } #ifdef HAS_FILESYSTEM_HTSP if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP)) { auto_ptr<CDVDDemuxHTSP> demuxer(new CDVDDemuxHTSP()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } #endif if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream; CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream(); if(pOtherStream) { /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pOtherStream)) return demuxer.release(); else return NULL; } } std::string filename = pInputStream->GetFileName(); /* Use PVR demuxer only for live streams */ if (filename.substr(0, 14) == "pvr://channels") { boost::shared_ptr<CPVRClient> client; if (g_PVRClients->GetPlayingClient(client) && client->HandlesDemuxing()) { auto_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } } auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; }