void printTimeCodes(const Option &opt, TrackEditor &track) { #ifdef _WIN32 utf8_codecvt_facet u8codec; std::wstring wname = m2w(opt.timecodeFile, utf8_codecvt_facet()); FILE *fp = std::strcmp(opt.timecodeFile, "-") ? _wfopen(wname.c_str(), L"w") : stdout; #else FILE *fp = std::strcmp(opt.timecodeFile, "-") ? std::fopen(opt.timecodeFile, "w") : stdout; #endif if (!fp) throw std::runtime_error("Can't open timecode file"); uint32_t timeScale = track.GetTimeScale(); std::fputs("# timecode format v2\n", fp); if (track.GetFrameCount()) { uint64_t off = track.CTS(0); for (size_t i = 0; i < track.GetFrameCount(); ++i) { uint64_t cts = track.CTS(i) - off; std::fprintf(fp, "%.15g\n", static_cast<double>(cts) / timeScale * 1000.0); } } std::fclose(fp); }
ALACSink::ALACSink(const std::wstring &path, EncoderBase &encoder) : m_mp4file(0), m_filename(path), m_closed(false) { static const char * const compatibleBrands[] = { "M4A ", "mp42" }; const AudioStreamBasicDescription &format = encoder.getOutputBasicDescription(); uint32_t sample_rate = static_cast<uint32_t>(format.mSampleRate); try { m_mp4file.Create( w2m(path, utf8_codecvt_facet()).c_str(), 0, // flags 1, // add_ftypes 0, // add_iods "M4A ", // majorBrand 0, // minorVersion const_cast<char**>(compatibleBrands), array_size(compatibleBrands)); m_mp4file.SetTimeScale(sample_rate); std::vector<char> cookie; encoder.getMagicCookie(&cookie); m_track_id = m_mp4file.AddAlacAudioTrack(sample_rate, reinterpret_cast<uint8_t*>(&cookie[20]), cookie.size() - 28); } catch (mp4v2::impl::MP4Error *e) { handle_mp4error(e); } }
void loadTimecodeV2(Option &option, size_t count) { std::wstring wfname = m2w(option.timecodeFile, utf8_codecvt_facet()); HANDLE fh = CreateFileW(wfname.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (fh == INVALID_HANDLE_VALUE) throw std::runtime_error("Can't open timecode file"); DWORD nread; char buffer[8192]; std::stringstream ss; while (ReadFile(fh, buffer, sizeof buffer, &nread, 0) && nread > 0) ss.write(buffer, nread); CloseHandle(fh); ss.seekg(0); parseTimecodeV2(option, ss, count); }
ALACSource::ALACSource(const std::wstring &path) : m_position(0) { try { m_file.Read(w2m(path, utf8_codecvt_facet()).c_str(), 0); m_track_id = m_file.FindTrackId(0, MP4_AUDIO_TRACK_TYPE); const char *type = m_file.GetTrackMediaDataName(m_track_id); if (std::strcmp(type, "alac")) throw std::runtime_error("Not an ALAC file"); const char *alacprop, *chanprop; const char *brand = m_file.GetStringProperty("ftyp.majorBrand"); if (!std::strcmp(brand, "qt ")) { // throw std::runtime_error("Not supported format"); alacprop = "mdia.minf.stbl.stsd.alac.wave.alac.decoderConfig"; chanprop = "mdia.minf.stbl.stsd.alac.wave.chan.data"; } else { alacprop = "mdia.minf.stbl.stsd.alac.alac.decoderConfig"; chanprop = "mdia.minf.stbl.stsd.alac.chan.data"; } std::vector<uint8_t> alac, chan; uint8_t *value; uint32_t size; m_file.GetTrackBytesProperty(m_track_id, alacprop, &value, &size); std::copy(value + 4, value + size, std::back_inserter(alac)); MP4Free(value); value = 0; try { m_file.GetTrackBytesProperty(m_track_id, chanprop, &value, &size); std::copy(value + 4, value + size, std::back_inserter(chan)); MP4Free(value); } catch (...) {} if (alac.size() != 24 || (chan.size() && chan.size() < 12)) throw std::runtime_error("ALACSource: invalid magic cookie"); std::memset(&m_format, 0, sizeof m_format); m_format.m_type = SampleFormat::kIsSignedInteger; m_format.m_endian = SampleFormat::kIsLittleEndian; m_format.m_nchannels = alac[9]; m_format.m_bitsPerSample = alac[5]; if (m_format.m_bitsPerSample == 20) m_format.m_bitsPerSample = 24; uint32_t timeScale; std::memcpy(&timeScale, &alac[20], 4); timeScale = b2host32(timeScale); m_format.m_rate = timeScale; AudioChannelLayout acl = { 0 }; if (chan.size()) { fourcc tag(reinterpret_cast<const char*>(&chan[0])); fourcc bitmap(reinterpret_cast<const char*>(&chan[4])); acl.mChannelLayoutTag = tag; acl.mChannelBitmap = bitmap; chanmap::GetChannels(&acl, &m_chanmap); } m_decoder = x::shared_ptr<ALACDecoder>(new ALACDecoder()); CHECKCA(m_decoder->Init(&alac[0], alac.size())); setRange(0, m_file.GetTrackDuration(m_track_id)); mp4a::fetchTags(m_file, &m_tags); } catch (mp4v2::impl::Exception *e) { handle_mp4error(e); } }