- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# MP4Splitter.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    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")); // ftyp
    00072         chkbytes.AddTail(_T("4,4,,6d6f6f76")); // moov
    00073         chkbytes.AddTail(_T("4,4,,6d646174")); // mdat
    00074         chkbytes.AddTail(_T("4,4,,736b6970")); // skip
    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); // "DllMain" of the dshow baseclasses;
    00093 }
    00094
    00095 #endif
    00096
    00097 //
    00098 // CMP4SplitterFilter
    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 = &empty;
    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 = &empty;
    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)) // TEMP
    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                                                 // mts.Add(mt); // TODO
    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 = &empty;
    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                 // FIXME: slow search & stss->m_Entries is private
    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                                                 // TODO: still very incomplete
    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)) // TEMP
    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                         // FIXME: slow search & stss->m_Entries is private
    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 // IKeyFrameInfo
    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 // CMP4SourceFilter
    00810 //
    00811
    00812 CMP4SourceFilter::CMP4SourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
    00813         : CMP4SplitterFilter(pUnk, phr)
    00814 {
    00815         m_clsid = __uuidof(this);
    00816         m_pInput.Free();
    00817 }