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 }

Generated on Tue Dec 13 14:47:20 2005 for guliverkli by  doxygen 1.4.5