00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "MP4Splitter.h"
00024 #include "..\..\..\DSUtil\DSUtil.h"
00025
00026 #include <initguid.h>
00027 #include "..\..\..\..\include\moreuuids.h"
00028
00029 #include "Ap4.h"
00030 #include "Ap4File.h"
00031 #include "Ap4StssAtom.h"
00032 #include "Ap4IsmaCryp.h"
00033 #include "Ap4AvcCAtom.h"
00034 #include "Ap4ChplAtom.h"
00035 #include "Ap4DataAtom.h"
00036
00037 #ifdef REGISTER_FILTER
00038
00039 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
00040 {
00041 {&MEDIATYPE_Stream, &MEDIASUBTYPE_MP4},
00042 {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
00043 };
00044
00045 const AMOVIESETUP_PIN sudpPins[] =
00046 {
00047 {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
00048 {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
00049 };
00050
00051 const AMOVIESETUP_FILTER sudFilter[] =
00052 {
00053 {&__uuidof(CMP4SplitterFilter), L"MP4 Splitter", MERIT_NORMAL, countof(sudpPins), sudpPins},
00054 {&__uuidof(CMP4SourceFilter), L"MP4 Source", MERIT_NORMAL, 0, NULL},
00055 };
00056
00057 CFactoryTemplate g_Templates[] =
00058 {
00059 {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CMP4SplitterFilter>, NULL, &sudFilter[0]},
00060 {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<CMP4SourceFilter>, NULL, &sudFilter[1]},
00061 };
00062
00063 int g_cTemplates = countof(g_Templates);
00064
00065 STDAPI DllRegisterServer()
00066 {
00067 DeleteRegKey(_T("Media Type\\Extensions\\"), _T(".mp4"));
00068
00069 CList<CString> chkbytes;
00070
00071 chkbytes.AddTail(_T("4,4,,66747970"));
00072 chkbytes.AddTail(_T("4,4,,6d6f6f76"));
00073 chkbytes.AddTail(_T("4,4,,6d646174"));
00074 chkbytes.AddTail(_T("4,4,,736b6970"));
00075
00076 RegisterSourceFilter(CLSID_AsyncReader, MEDIASUBTYPE_MP4, chkbytes, NULL);
00077
00078 return AMovieDllRegisterServer2(TRUE);
00079 }
00080
00081 STDAPI DllUnregisterServer()
00082 {
00083 UnRegisterSourceFilter(MEDIASUBTYPE_MP4);
00084
00085 return AMovieDllRegisterServer2(FALSE);
00086 }
00087
00088 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
00089
00090 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
00091 {
00092 return DllEntryPoint((HINSTANCE)hModule, dwReason, 0);
00093 }
00094
00095 #endif
00096
00097
00098
00099
00100
00101 CMP4SplitterFilter::CMP4SplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
00102 : CBaseSplitterFilter(NAME("CMP4SplitterFilter"), pUnk, phr, __uuidof(this))
00103 {
00104 }
00105
00106 CMP4SplitterFilter::~CMP4SplitterFilter()
00107 {
00108 }
00109
00110 HRESULT CMP4SplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
00111 {
00112 CheckPointer(pAsyncReader, E_POINTER);
00113
00114 HRESULT hr = E_FAIL;
00115
00116 m_trackpos.RemoveAll();
00117
00118 m_pFile.Free();
00119 m_pFile.Attach(new CMP4SplitterFile(pAsyncReader, hr));
00120 if(!m_pFile) return E_OUTOFMEMORY;
00121 if(FAILED(hr)) {m_pFile.Free(); return hr;}
00122
00123 m_rtNewStart = m_rtCurrent = 0;
00124 m_rtNewStop = m_rtStop = m_rtDuration = 0;
00125
00126 if(AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie())
00127 {
00128 for(AP4_List<AP4_Track>::Item* item = movie->GetTracks().FirstItem();
00129 item;
00130 item = item->GetNext())
00131 {
00132 AP4_Track* track = item->GetData();
00133
00134 if(track->GetType() != AP4_Track::TYPE_VIDEO
00135 && track->GetType() != AP4_Track::TYPE_AUDIO
00136 && track->GetType() != AP4_Track::TYPE_TEXT)
00137 continue;
00138
00139 AP4_Sample sample;
00140
00141 if(!AP4_SUCCEEDED(track->GetSample(0, sample)) || sample.GetDescriptionIndex() == 0xFFFFFFFF)
00142 continue;
00143
00144 CArray<CMediaType> mts;
00145
00146 CMediaType mt;
00147 mt.SetSampleSize(1);
00148
00149 VIDEOINFOHEADER* vih = NULL;
00150 WAVEFORMATEX* wfe = NULL;
00151
00152 AP4_DataBuffer empty;
00153
00154 if(AP4_SampleDescription* desc = track->GetSampleDescription(sample.GetDescriptionIndex()))
00155 {
00156 AP4_MpegSampleDescription* mpeg_desc = NULL;
00157
00158 if(desc->GetType() == AP4_SampleDescription::TYPE_MPEG)
00159 {
00160 mpeg_desc = dynamic_cast<AP4_MpegSampleDescription*>(desc);
00161 }
00162 else if(desc->GetType() == AP4_SampleDescription::TYPE_ISMACRYP)
00163 {
00164 AP4_IsmaCrypSampleDescription* isma_desc = dynamic_cast<AP4_IsmaCrypSampleDescription*>(desc);
00165 mpeg_desc = isma_desc->GetOriginalSampleDescription();
00166 }
00167
00168 if(AP4_MpegVideoSampleDescription* video_desc =
00169 dynamic_cast<AP4_MpegVideoSampleDescription*>(mpeg_desc))
00170 {
00171 const AP4_DataBuffer* di = video_desc->GetDecoderInfo();
00172 if(!di) di = ∅
00173
00174 mt.majortype = MEDIATYPE_Video;
00175 mt.formattype = FORMAT_VideoInfo;
00176 vih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + di->GetDataSize());
00177 memset(vih, 0, mt.FormatLength());
00178 vih->dwBitRate = video_desc->GetAvgBitrate()/8;
00179 vih->bmiHeader.biSize = sizeof(vih->bmiHeader);
00180 vih->bmiHeader.biWidth = (LONG)video_desc->GetWidth();
00181 vih->bmiHeader.biHeight = (LONG)video_desc->GetHeight();
00182 memcpy(vih + 1, di->GetData(), di->GetDataSize());
00183
00184 switch(video_desc->GetObjectTypeId())
00185 {
00186 case AP4_MPEG4_VISUAL_OTI:
00187 mt.subtype = FOURCCMap('v4pm');
00188 mt.formattype = FORMAT_MPEG2Video;
00189 {
00190 MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + di->GetDataSize());
00191 memset(vih, 0, mt.FormatLength());
00192 vih->hdr.bmiHeader.biSize = sizeof(vih->hdr.bmiHeader);
00193 vih->hdr.bmiHeader.biWidth = (LONG)video_desc->GetWidth();
00194 vih->hdr.bmiHeader.biHeight = (LONG)video_desc->GetHeight();
00195 vih->hdr.bmiHeader.biCompression = 'v4pm';
00196 vih->hdr.bmiHeader.biPlanes = 1;
00197 vih->hdr.bmiHeader.biBitCount = 24;
00198 vih->hdr.dwPictAspectRatioX = vih->hdr.bmiHeader.biWidth;
00199 vih->hdr.dwPictAspectRatioY = vih->hdr.bmiHeader.biHeight;
00200 vih->cbSequenceHeader = di->GetDataSize();
00201 memcpy(vih->dwSequenceHeader, di->GetData(), di->GetDataSize());
00202 mts.Add(mt);
00203 mt.subtype = FOURCCMap(vih->hdr.bmiHeader.biCompression = 'V4PM');
00204 mts.Add(mt);
00205 }
00206 break;
00207 case AP4_MPEG2_VISUAL_SIMPLE_OTI:
00208 case AP4_MPEG2_VISUAL_MAIN_OTI:
00209 case AP4_MPEG2_VISUAL_SNR_OTI:
00210 case AP4_MPEG2_VISUAL_SPATIAL_OTI:
00211 case AP4_MPEG2_VISUAL_HIGH_OTI:
00212 case AP4_MPEG2_VISUAL_422_OTI:
00213 mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO;
00214 {
00215 m_pFile->Seek(sample.GetOffset());
00216 CBaseSplitterFileEx::seqhdr h;
00217 CMediaType mt2;
00218 if(m_pFile->Read(h, sample.GetSize(), &mt2))
00219 mt = mt2;
00220 }
00221 mts.Add(mt);
00222 break;
00223 case AP4_MPEG1_VISUAL_OTI:
00224 mt.subtype = MEDIASUBTYPE_MPEG1Payload;
00225 {
00226 m_pFile->Seek(sample.GetOffset());
00227 CBaseSplitterFileEx::seqhdr h;
00228 CMediaType mt2;
00229 if(m_pFile->Read(h, sample.GetSize(), &mt2))
00230 mt = mt2;
00231 }
00232 mts.Add(mt);
00233 break;
00234 }
00235
00236 if(mt.subtype == GUID_NULL)
00237 {
00238 TRACE(_T("Unknown video OBI: %02x\n"), video_desc->GetObjectTypeId());
00239 }
00240 }
00241 else if(AP4_MpegAudioSampleDescription* audio_desc =
00242 dynamic_cast<AP4_MpegAudioSampleDescription*>(mpeg_desc))
00243 {
00244 const AP4_DataBuffer* di = audio_desc->GetDecoderInfo();
00245 if(!di) di = ∅
00246
00247 mt.majortype = MEDIATYPE_Audio;
00248 mt.formattype = FORMAT_WaveFormatEx;
00249
00250 wfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX) + di->GetDataSize());
00251 memset(wfe, 0, mt.FormatLength());
00252 wfe->nSamplesPerSec = audio_desc->GetSampleRate();
00253 wfe->nAvgBytesPerSec = audio_desc->GetAvgBitrate()/8;
00254 wfe->nChannels = audio_desc->GetChannelCount();
00255 wfe->wBitsPerSample = audio_desc->GetSampleSize();
00256 wfe->cbSize = (WORD)di->GetDataSize();
00257 memcpy(wfe + 1, di->GetData(), di->GetDataSize());
00258
00259 switch(audio_desc->GetObjectTypeId())
00260 {
00261 case AP4_MPEG4_AUDIO_OTI:
00262 case AP4_MPEG2_AAC_AUDIO_MAIN_OTI:
00263 case AP4_MPEG2_AAC_AUDIO_LC_OTI:
00264 case AP4_MPEG2_AAC_AUDIO_SSRP_OTI:
00265 mt.subtype = FOURCCMap(wfe->wFormatTag = WAVE_FORMAT_AAC);
00266 mts.Add(mt);
00267 break;
00268 case AP4_MPEG2_PART3_AUDIO_OTI:
00269 break;
00270 case AP4_MPEG1_AUDIO_OTI:
00271 mt.subtype = FOURCCMap(wfe->wFormatTag = WAVE_FORMAT_MP3);
00272 {
00273 m_pFile->Seek(sample.GetOffset());
00274 CBaseSplitterFileEx::mpahdr h;
00275 CMediaType mt2;
00276 if(m_pFile->Read(h, sample.GetSize(), false, &mt2))
00277 mt = mt2;
00278 }
00279 mts.Add(mt);
00280 break;
00281 }
00282
00283 if(mt.subtype == GUID_NULL)
00284 {
00285 TRACE(_T("Unknown audio OBI: %02x\n"), audio_desc->GetObjectTypeId());
00286 }
00287 }
00288 else if(AP4_UnknownSampleDescription* unknown_desc =
00289 dynamic_cast<AP4_UnknownSampleDescription*>(desc))
00290 {
00291 AP4_SampleEntry* sample_entry = unknown_desc->GetSampleEntry();
00292
00293 if(dynamic_cast<AP4_TextSampleEntry*>(sample_entry)
00294 || dynamic_cast<AP4_Tx3gSampleEntry*>(sample_entry))
00295 {
00296 mt.majortype = MEDIATYPE_Subtitle;
00297 mt.subtype = MEDIASUBTYPE_ASS;
00298 mt.formattype = FORMAT_SubtitleInfo;
00299 CStringA hdr = "[Script Info]\nScriptType: v4.00+\n";
00300 SUBTITLEINFO* si = (SUBTITLEINFO*)mt.AllocFormatBuffer(sizeof(SUBTITLEINFO) + hdr.GetLength());
00301 memset(si, 0, mt.FormatLength());
00302 si->dwOffset = sizeof(SUBTITLEINFO);
00303 strcpy_s(si->IsoLang, countof(si->IsoLang), track->GetTrackLanguage().c_str());
00304 wcscpy_s(si->TrackName, countof(si->TrackName), CStringW(track->GetTrackName().c_str()));
00305 memcpy(si + 1, (LPCSTR)hdr, hdr.GetLength());
00306
00307
00308 mt.subtype = MEDIASUBTYPE_UTF8;
00309 si = (SUBTITLEINFO*)mt.ReallocFormatBuffer(sizeof(SUBTITLEINFO));
00310 mts.Add(mt);
00311 }
00312 }
00313 }
00314 else if(AP4_Avc1SampleEntry* avc1 = dynamic_cast<AP4_Avc1SampleEntry*>(
00315 track->GetTrakAtom()->FindChild("mdia/minf/stbl/stsd/avc1")))
00316 {
00317 if(AP4_AvcCAtom* avcC = dynamic_cast<AP4_AvcCAtom*>(avc1->GetChild(AP4_ATOM_TYPE_AVCC)))
00318 {
00319 const AP4_DataBuffer* di = avcC->GetDecoderInfo();
00320 if(!di) di = ∅
00321
00322 const AP4_Byte* data = di->GetData();
00323 AP4_Size size = di->GetDataSize();
00324
00325 mt.majortype = MEDIATYPE_Video;
00326 mt.subtype = FOURCCMap('1cva');
00327 mt.formattype = FORMAT_MPEG2Video;
00328
00329 MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + size - 7);
00330 memset(vih, 0, mt.FormatLength());
00331 vih->hdr.bmiHeader.biSize = sizeof(vih->hdr.bmiHeader);
00332 vih->hdr.bmiHeader.biWidth = (LONG)avc1->GetWidth();
00333 vih->hdr.bmiHeader.biHeight = (LONG)avc1->GetHeight();
00334 vih->hdr.bmiHeader.biCompression = '1cva';
00335 vih->hdr.bmiHeader.biPlanes = 1;
00336 vih->hdr.bmiHeader.biBitCount = 24;
00337 vih->hdr.dwPictAspectRatioX = vih->hdr.bmiHeader.biWidth;
00338 vih->hdr.dwPictAspectRatioY = vih->hdr.bmiHeader.biHeight;
00339 vih->dwProfile = data[1];
00340 vih->dwLevel = data[3];
00341 vih->dwFlags = (data[4] & 3) + 1;
00342
00343 vih->cbSequenceHeader = 0;
00344
00345 BYTE* src = (BYTE*)data + 5;
00346 BYTE* dst = (BYTE*)vih->dwSequenceHeader;
00347
00348 BYTE* src_end = (BYTE*)data + size;
00349 BYTE* dst_end = (BYTE*)vih->dwSequenceHeader + size;
00350
00351 for(int i = 0; i < 2; i++)
00352 {
00353 for(int n = *src++ & 0x1f; n > 0; n--)
00354 {
00355 int len = ((src[0] << 8) | src[1]) + 2;
00356 if(src + len > src_end || dst + len > dst_end) {ASSERT(0); break;}
00357 memcpy(dst, src, len);
00358 src += len;
00359 dst += len;
00360 vih->cbSequenceHeader += len;
00361 }
00362 }
00363
00364 mts.Add(mt);
00365
00366 mt.subtype = FOURCCMap(vih->hdr.bmiHeader.biCompression = '1CVA');
00367 mts.Add(mt);
00368 }
00369 }
00370 else if(AP4_VisualSampleEntry* s263 = dynamic_cast<AP4_VisualSampleEntry*>(
00371 track->GetTrakAtom()->FindChild("mdia/minf/stbl/stsd/s263")))
00372 {
00373 mt.majortype = MEDIATYPE_Video;
00374 mt.subtype = FOURCCMap('362s');
00375 mt.formattype = FORMAT_VideoInfo;
00376 vih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
00377 memset(vih, 0, mt.FormatLength());
00378 vih->bmiHeader.biSize = sizeof(vih->bmiHeader);
00379 vih->bmiHeader.biWidth = (LONG)s263->GetWidth();
00380 vih->bmiHeader.biHeight = (LONG)s263->GetHeight();
00381 vih->bmiHeader.biCompression = '362s';
00382 mts.Add(mt);
00383
00384 mt.subtype = FOURCCMap(vih->bmiHeader.biCompression = '362S');
00385 mts.Add(mt);
00386 }
00387 else if(AP4_AudioSampleEntry* samr = dynamic_cast<AP4_AudioSampleEntry*>(
00388 track->GetTrakAtom()->FindChild("mdia/minf/stbl/stsd/samr")))
00389 {
00390 mt.majortype = MEDIATYPE_Audio;
00391 mt.subtype = FOURCCMap('rmas');
00392 mt.formattype = FORMAT_WaveFormatEx;
00393 wfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX));
00394 memset(wfe, 0, mt.FormatLength());
00395 wfe->nSamplesPerSec = samr->GetSampleRate();
00396 wfe->nChannels = samr->GetChannelCount();
00397 mts.Add(mt);
00398
00399 mt.subtype = FOURCCMap('RMAS');
00400 mts.Add(mt);
00401 }
00402
00403 REFERENCE_TIME rtDuration = 10000i64 * track->GetDurationMs();
00404 if(m_rtDuration < rtDuration) m_rtDuration = rtDuration;
00405
00406 DWORD id = track->GetId();
00407
00408 CStringW name, lang;
00409 name.Format(L"Output %d", id);
00410
00411 AP4_String TrackName = track->GetTrackName();
00412 AP4_String TrackLanguage = track->GetTrackLanguage();
00413
00414 if(!TrackName.empty())
00415 {
00416 name.Format(L"%s", CStringW(TrackName.c_str()));
00417 SetProperty(L"NAME", CStringW(TrackName.c_str()));
00418 }
00419
00420 if(!TrackLanguage.empty())
00421 {
00422 if(TrackLanguage != "und") name += L" (" + CStringW(TrackLanguage.c_str()) + L")";
00423 SetProperty(L"LANG", CStringW(TrackLanguage.c_str()));
00424 }
00425
00426 CAutoPtr<CBaseSplitterOutputPin> pPinOut(new CBaseSplitterOutputPin(mts, name, this, this, &hr));
00427
00428 EXECUTE_ASSERT(SUCCEEDED(AddOutputPin(id, pPinOut)));
00429
00430 m_trackpos[id] = trackpos();
00431 }
00432
00433 if(AP4_ChplAtom* chpl = dynamic_cast<AP4_ChplAtom*>(movie->GetMoovAtom()->FindChild("udta/chpl")))
00434 {
00435 AP4_Array<AP4_ChplAtom::AP4_Chapter>& chapters = chpl->GetChapters();
00436
00437 for(AP4_Cardinal i = 0; i < chapters.ItemCount(); i++)
00438 {
00439 AP4_ChplAtom::AP4_Chapter& chapter = chapters[i];
00440 ChapAppend(chapter.Time, UTF8To16(ConvertMBCS(chapter.Name.c_str(), ANSI_CHARSET, CP_UTF8)));
00441 }
00442
00443 ChapSort();
00444 }
00445
00446 if(AP4_ContainerAtom* ilst = dynamic_cast<AP4_ContainerAtom*>(movie->GetMoovAtom()->FindChild("udta/meta/ilst")))
00447 {
00448 CStringW title, artist, writer, album, year, appl, desc, track;
00449
00450 for(AP4_List<AP4_Atom>::Item* item = ilst->GetChildren().FirstItem();
00451 item;
00452 item = item->GetNext())
00453 {
00454 if(AP4_ContainerAtom* atom = dynamic_cast<AP4_ContainerAtom*>(item->GetData()))
00455 {
00456 if(AP4_DataAtom* data = dynamic_cast<AP4_DataAtom*>(atom->GetChild(AP4_ATOM_TYPE_DATA)))
00457 {
00458 const AP4_DataBuffer* db = data->GetData();
00459
00460 if(atom->GetType() == AP4_ATOM_TYPE_TRKN)
00461 {
00462 if(db->GetDataSize() >= 4)
00463 {
00464 unsigned short n = (db->GetData()[2] << 8) | db->GetData()[3];
00465 if(n > 0 && n < 100) track.Format(L"%02d", n);
00466 else if(n >= 100) track.Format(L"%d", n);
00467 }
00468 }
00469 else
00470 {
00471 CStringW str = UTF8To16(CStringA((LPCSTR)db->GetData(), db->GetDataSize()));
00472
00473 switch(atom->GetType())
00474 {
00475 case AP4_ATOM_TYPE_NAM: title = str; break;
00476 case AP4_ATOM_TYPE_ART: artist = str; break;
00477 case AP4_ATOM_TYPE_WRT: writer = str; break;
00478 case AP4_ATOM_TYPE_ALB: album = str; break;
00479 case AP4_ATOM_TYPE_DAY: year = str; break;
00480 case AP4_ATOM_TYPE_TOO: appl = str; break;
00481 case AP4_ATOM_TYPE_CMT: desc = str; break;
00482 }
00483 }
00484 }
00485 }
00486 }
00487
00488 if(!title.IsEmpty())
00489 {
00490 if(!track.IsEmpty()) title = track + L" - " + title;
00491 if(!album.IsEmpty()) title = album + L" - " + title;
00492 if(!year.IsEmpty()) title += L" - " + year;
00493 SetProperty(L"TITL", title);
00494 }
00495
00496 if(!artist.IsEmpty()) SetProperty(L"AUTH", artist);
00497 else if(!writer.IsEmpty()) SetProperty(L"AUTH", writer);
00498
00499 if(!appl.IsEmpty()) SetProperty(L"APPL", appl);
00500
00501 if(!desc.IsEmpty()) SetProperty(L"DESC", desc);
00502 }
00503 }
00504
00505 m_rtNewStop = m_rtStop = m_rtDuration;
00506
00507 return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
00508 }
00509
00510 bool CMP4SplitterFilter::DemuxInit()
00511 {
00512 AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
00513
00514 POSITION pos = m_trackpos.GetStartPosition();
00515 while(pos)
00516 {
00517 CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
00518
00519 pPair->m_value.index = 0;
00520 pPair->m_value.ts = 0;
00521
00522 AP4_Track* track = movie->GetTrack(pPair->m_key);
00523
00524 AP4_Sample sample;
00525 if(AP4_SUCCEEDED(track->GetSample(0, sample)))
00526 pPair->m_value.ts = sample.GetCts();
00527 }
00528
00529 return true;
00530 }
00531
00532 void CMP4SplitterFilter::DemuxSeek(REFERENCE_TIME rt)
00533 {
00534 AP4_TimeStamp ts = (AP4_TimeStamp)(rt / 10000);
00535
00536 AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
00537
00538 POSITION pos = m_trackpos.GetStartPosition();
00539 while(pos)
00540 {
00541 CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
00542
00543 AP4_Track* track = movie->GetTrack(pPair->m_key);
00544
00545 if(AP4_FAILED(track->GetSampleIndexForTimeStampMs(ts, pPair->m_value.index)))
00546 pPair->m_value.index = 0;
00547
00548 AP4_Sample sample;
00549 if(AP4_SUCCEEDED(track->GetSample(pPair->m_value.index, sample)))
00550 pPair->m_value.ts = sample.GetCts();
00551
00552
00553
00554 if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
00555 {
00556 if(stss->m_Entries.ItemCount() > 0)
00557 {
00558 AP4_Cardinal i = -1;
00559 while(++i < stss->m_Entries.ItemCount() && stss->m_Entries[i]-1 <= pPair->m_value.index);
00560 if(i > 0) i--;
00561 pPair->m_value.index = stss->m_Entries[i]-1;
00562 }
00563 }
00564 }
00565 }
00566
00567 bool CMP4SplitterFilter::DemuxLoop()
00568 {
00569 HRESULT hr = S_OK;
00570
00571 AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
00572
00573 while(SUCCEEDED(hr) && !CheckRequest(NULL))
00574 {
00575 CAtlMap<DWORD, trackpos>::CPair* pPairNext = NULL;
00576 REFERENCE_TIME rtNext = 0;
00577
00578 POSITION pos = m_trackpos.GetStartPosition();
00579 while(pos)
00580 {
00581 CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
00582
00583 AP4_Track* track = movie->GetTrack(pPair->m_key);
00584
00585 REFERENCE_TIME rt = (REFERENCE_TIME)(10000000.0 / track->GetMediaTimeScale() * pPair->m_value.ts);
00586
00587 if(pPair->m_value.index < track->GetSampleCount() && (!pPairNext || rt < rtNext))
00588 {
00589 pPairNext = pPair;
00590 rtNext = rt;
00591 }
00592 }
00593
00594 if(!pPairNext) break;
00595
00596 AP4_Track* track = movie->GetTrack(pPairNext->m_key);
00597
00598 AP4_Sample sample;
00599 AP4_DataBuffer data;
00600
00601 if(AP4_SUCCEEDED(track->ReadSample(pPairNext->m_value.index, sample, data)))
00602 {
00603 CAutoPtr<Packet> p(new Packet());
00604
00605 p->TrackNumber = (DWORD)track->GetId();
00606 p->rtStart = (REFERENCE_TIME)(10000000.0 / track->GetMediaTimeScale() * sample.GetCts());
00607 p->rtStop = p->rtStart + 1;
00608 p->bSyncPoint = TRUE;
00609
00610 if(track->GetType() == AP4_Track::TYPE_TEXT)
00611 {
00612 const AP4_Byte* ptr = data.GetData();
00613 AP4_Size avail = data.GetDataSize();
00614
00615 if(avail > 2)
00616 {
00617 AP4_UI16 size = (ptr[0] << 8) | ptr[1];
00618
00619 if(size <= avail-2)
00620 {
00621 CStringA str;
00622
00623 if(size >= 2 && ptr[2] == 0xfe && ptr[3] == 0xff)
00624 {
00625 CStringW wstr = CStringW((LPCWSTR)&ptr[2], size/2);
00626 for(int i = 0; i < wstr.GetLength(); i++) wstr.SetAt(i, ((WORD)wstr[i] >> 8) | ((WORD)wstr[i] << 8));
00627 str = UTF16To8(wstr);
00628 }
00629 else
00630 {
00631 str = CStringA((LPCSTR)&ptr[2], size);
00632 }
00633
00634
00635
00636 if(CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber))
00637 if(pPin->CurrentMediaType().subtype == MEDIASUBTYPE_ASS)
00638 {
00639 CStringW wstr = UTF8To16(str);
00640
00641 AP4_SampleDescription* desc = track->GetSampleDescription(sample.GetDescriptionIndex());
00642
00643 if(AP4_UnknownSampleDescription* unknown_desc = dynamic_cast<AP4_UnknownSampleDescription*>(desc))
00644 {
00645 AP4_SampleEntry* sample_entry = unknown_desc->GetSampleEntry();
00646
00647 if(AP4_TextSampleEntry* text = dynamic_cast<AP4_TextSampleEntry*>(sample_entry))
00648 {
00649 const AP4_TextSampleEntry::AP4_TextDescription& d = text->GetDescription();
00650 }
00651 else if(AP4_Tx3gSampleEntry* tx3g = dynamic_cast<AP4_Tx3gSampleEntry*>(sample_entry))
00652 {
00653 const AP4_Tx3gSampleEntry::AP4_Tx3gDescription& d = tx3g->GetDescription();
00654
00655 int align = 2;
00656 signed char h = (signed char)d.HorizontalJustification;
00657 signed char v = (signed char)d.VerticalJustification;
00658 if(h == 0 && v < 0) align = 1;
00659 else if(h > 0 && v < 0) align = 2;
00660 else if(h < 0 && v < 0) align = 3;
00661 else if(h == 0 && v > 0) align = 4;
00662 else if(h > 0 && v > 0) align = 5;
00663 else if(h < 0 && v > 0) align = 6;
00664 else if(h == 0 && v == 0) align = 7;
00665 else if(h > 0 && v == 0) align = 8;
00666 else if(h < 0 && v == 0) align = 9;
00667 wstr.Format(L"{\\an%d}%s", align, CStringW(wstr));
00668
00669 if(d.BackgroundColor)
00670 {
00671 DWORD c = d.BackgroundColor;
00672 wstr.Format(L"{\\3c%02x%02x%02x}%s", (c>>8)&0xff, (c>>16)&0xff, (c>>24)&0xff, CStringW(wstr));
00673 if(c&0xff) wstr.Format(L"{\\3a%02x}%s", 255 - (c&0xff), CStringW(wstr));
00674 }
00675
00676 if(d.Style.Font.Color)
00677 {
00678 DWORD c = d.Style.Font.Color;
00679 wstr.Format(L"{\\1c%02x%02x%02x}%s", (c>>8)&0xff, (c>>16)&0xff, (c>>24)&0xff, CStringW(wstr));
00680 if(c&0xff) wstr.Format(L"{\\1a%02x}%s", 255 - (c&0xff), CStringW(wstr));
00681 }
00682
00683 if(d.Style.Font.Size) wstr.Format(L"{\\fs%d}%s", d.Style.Font.Size, CStringW(wstr));
00684
00685 if(d.Style.Font.Face&1) wstr = L"{\\b1}" + wstr;
00686 if(d.Style.Font.Face&2) wstr = L"{\\i1}" + wstr;
00687 if(d.Style.Font.Face&4) wstr = L"{\\u1}" + wstr;
00688 }
00689 }
00690
00691 str = "0,0,Default,,0000,0000,0000,," + UTF16To8(wstr);
00692 }
00693
00694 p->pData.SetSize(str.GetLength());
00695 memcpy(p->pData.GetData(), (LPCSTR)str, str.GetLength());
00696
00697 AP4_Sample sample;
00698 if(AP4_SUCCEEDED(track->GetSample(pPairNext->m_value.index+1, sample)))
00699 p->rtStop = (REFERENCE_TIME)(10000000.0 / track->GetMediaTimeScale() * sample.GetCts());
00700 }
00701 }
00702 }
00703 else
00704 {
00705 p->pData.SetSize(data.GetDataSize());
00706 memcpy(p->pData.GetData(), data.GetData(), data.GetDataSize());
00707 }
00708
00709
00710
00711 if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
00712 {
00713 if(stss->m_Entries.ItemCount() > 0)
00714 {
00715 p->bSyncPoint = FALSE;
00716
00717 AP4_Cardinal i = -1;
00718 while(++i < stss->m_Entries.ItemCount())
00719 if(stss->m_Entries[i]-1 == pPairNext->m_value.index)
00720 p->bSyncPoint = TRUE;
00721 }
00722 }
00723
00724 hr = DeliverPacket(p);
00725 }
00726
00727 {
00728 AP4_Sample sample;
00729 if(AP4_SUCCEEDED(track->GetSample(++pPairNext->m_value.index, sample)))
00730 pPairNext->m_value.ts = sample.GetCts();
00731 }
00732
00733 }
00734
00735 return true;
00736 }
00737
00738
00739
00740 STDMETHODIMP CMP4SplitterFilter::GetKeyFrameCount(UINT& nKFs)
00741 {
00742 CheckPointer(m_pFile, E_UNEXPECTED);
00743
00744 if(!m_pFile) return E_UNEXPECTED;
00745
00746 AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
00747
00748 POSITION pos = m_trackpos.GetStartPosition();
00749 while(pos)
00750 {
00751 CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
00752
00753 AP4_Track* track = movie->GetTrack(pPair->m_key);
00754
00755 if(track->GetType() != AP4_Track::TYPE_VIDEO)
00756 continue;
00757
00758 if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
00759 {
00760 nKFs = stss->m_Entries.ItemCount();
00761 return S_OK;
00762 }
00763 }
00764
00765 return E_FAIL;
00766 }
00767
00768 STDMETHODIMP CMP4SplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
00769 {
00770 CheckPointer(pFormat, E_POINTER);
00771 CheckPointer(pKFs, E_POINTER);
00772 CheckPointer(m_pFile, E_UNEXPECTED);
00773
00774 if(*pFormat != TIME_FORMAT_MEDIA_TIME) return E_INVALIDARG;
00775
00776 if(!m_pFile) return E_UNEXPECTED;
00777
00778 AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
00779
00780 POSITION pos = m_trackpos.GetStartPosition();
00781 while(pos)
00782 {
00783 CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
00784
00785 AP4_Track* track = movie->GetTrack(pPair->m_key);
00786
00787 if(track->GetType() != AP4_Track::TYPE_VIDEO)
00788 continue;
00789
00790 if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
00791 {
00792 nKFs = 0;
00793
00794 for(AP4_Cardinal i = 0; i < stss->m_Entries.ItemCount(); i++)
00795 {
00796 AP4_Sample sample;
00797 if(AP4_SUCCEEDED(track->GetSample(stss->m_Entries[i]-1, sample)))
00798 pKFs[nKFs++] = 10000000i64 * sample.GetCts() / track->GetMediaTimeScale();
00799 }
00800
00801 return S_OK;
00802 }
00803 }
00804
00805 return E_FAIL;
00806 }
00807
00808
00809
00810
00811
00812 CMP4SourceFilter::CMP4SourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
00813 : CMP4SplitterFilter(pUnk, phr)
00814 {
00815 m_clsid = __uuidof(this);
00816 m_pInput.Free();
00817 }