Пример #1
0
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);
    }
}
Пример #2
0
void ALACSink::close()
{
    if (!m_closed) {
	m_closed = true;
	try {
	    m_mp4file.Close();
	} catch (mp4v2::impl::MP4Error *e) {
	    handle_mp4error(e);
	}
    }
}
Пример #3
0
size_t ALACSource::readSamples(void *buffer, size_t nsamples)
{
    uint32_t bpf = m_asbd.mBytesPerFrame;

    if (!m_buffer.count()) {
        uint32_t size;
        MP4SampleId sid;
        try {
            sid = m_file.GetSampleIdFromTime(m_track_id, m_position);
            size = m_file.GetSampleSize(m_track_id, sid);
        } catch (mp4v2::impl::Exception *e) {
            delete e;
            return 0;
        }
        MP4Timestamp start;
        MP4Duration duration;
        std::vector<uint8_t> ivec(size);
        uint8_t *vp = &ivec[0];

        try {
            m_file.ReadSample(m_track_id, sid, &vp, &size, &start,
                              &duration);
        } catch (mp4v2::impl::Exception *e) {
            handle_mp4error(e);
        }
        BitBuffer bits;
        BitBufferInit(&bits, vp, size);
        m_buffer.resize(duration);
        uint32_t ncount;
        CHECKCA(m_decoder->Decode(&bits, m_buffer.write_ptr(),
                                  duration, m_asbd.mChannelsPerFrame,
                                  &ncount));
        m_buffer.commit(ncount);
        m_buffer.advance(m_position - start);
    }
    uint32_t count = std::min(m_buffer.count(),
                              static_cast<uint32_t>(nsamples));
    size_t nbytes = count * bpf;
    util::unpack(m_buffer.read_ptr(), buffer, &nbytes,
                 m_asbd.mBytesPerFrame / m_asbd.mChannelsPerFrame,
                 m_oasbd.mBytesPerFrame / m_oasbd.mChannelsPerFrame);
    m_buffer.advance(count);
    m_position += count;
    return count;
}
Пример #4
0
ALACSource::ALACSource(const std::shared_ptr<FILE> &fp)
    : m_position(0), m_fp(fp)
{
    try {
        int fd = fileno(m_fp.get());
        {
            util::FilePositionSaver _(fd);
            _lseeki64(fd, 0, SEEK_SET);
            char buf[8];
            if (read(fd, buf, 8) != 8 || std::memcmp(&buf[4], "ftyp", 4))
                throw std::runtime_error("Not an MP4 file");
        }
        static MP4FDReadProvider provider;
        std::string name = strutil::format("%d", fd);
        m_file.Read(name.c_str(), &provider);
        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");

        uint32_t timeScale;
        std::memcpy(&timeScale, &alac[20], 4);
        timeScale = util::b2host32(timeScale);
        m_asbd = cautil::buildASBDForPCM(timeScale, alac[9], alac[5],
                                    kAudioFormatFlagIsSignedInteger,
                                    kAudioFormatFlagIsAlignedHigh);
        m_oasbd = cautil::buildASBDForPCM2(timeScale, alac[9], alac[5],
                                           32, kAudioFormatFlagIsSignedInteger);

        m_buffer.units_per_packet = m_asbd.mBytesPerFrame;

        AudioChannelLayout acl = { 0 };
        if (chan.size()) {
            util::fourcc tag(reinterpret_cast<const char*>(&chan[0]));
            util::fourcc bitmap(reinterpret_cast<const char*>(&chan[4]));
            acl.mChannelLayoutTag = tag;
            acl.mChannelBitmap = bitmap;
            chanmap::getChannels(&acl, &m_chanmap);
        }
        m_decoder = std::shared_ptr<ALACDecoder>(new ALACDecoder());
        CHECKCA(m_decoder->Init(&alac[0], alac.size()));
        m_length = m_file.GetTrackDuration(m_track_id);

        mp4a::fetchTags(m_file, &m_tags);
    } catch (mp4v2::impl::Exception *e) {
        handle_mp4error(e);
    }
}
Пример #5
0
void execute(Option &opt)
{
    try {
        //mp4v2::impl::log.setVerbosity(MP4_LOG_VERBOSE3);
        mp4v2::impl::log.setVerbosity(MP4_LOG_NONE);
        mp4v2::impl::MP4File file;
        std::fprintf(stderr, "Reading MP4 stream...\n");
        if (opt.inplace)
            file.Modify(opt.src);
        else
            file.Read(opt.src, 0);
        std::fprintf(stderr, "Done reading\n");
        MP4TrackId trackId = file.FindTrackId(0, MP4_VIDEO_TRACK_TYPE);
        mp4v2::impl::MP4Track *track = file.GetTrack(trackId);
        // XXX
        TrackEditor editor(reinterpret_cast<MP4TrackX*>(track));
        opt.originalTimeScale = editor.GetTimeScale();
        if (opt.printOnly) {
            printTimeCodes(opt, editor);
            return;
        }
        editor.SetAudioDelay(opt.audioDelay);
        if (opt.compressDTS)
            editor.EnableDTSCompression(true);
        if (opt.ranges.size())
            editor.SetFPS(&opt.ranges[0], opt.ranges.size(),
                          opt.requestedTimeScale);
        else if (opt.timecodeFile || opt.modified()) {
            if (opt.timecodeFile)
                loadTimecodeV2(opt, editor.GetFrameCount() + 1);
            else {
                uint64_t off = editor.CTS(0);
                opt.timeScale = opt.originalTimeScale;
                for (size_t i = 0; i < editor.GetFrameCount() + 1; ++i)
                    opt.timecodes.push_back(editor.CTS(i) - off);
                if (opt.optimizeTimecode)
                    averageTimecode(opt);
            }
            if (opt.optimizeTimecode && convertToExactRanges(opt))
                editor.SetFPS(&opt.ranges[0], opt.ranges.size(),
                              opt.requestedTimeScale);
            else {
                rescaleTimecode(opt);
                editor.SetTimeCodes(&opt.timecodes[0],
                        opt.timecodes.size(),
                        opt.timeScale);
            }
        }
        if (opt.modified()) {
            editor.AdjustTimeCodes();
            editor.DoEditTimeCodes();
        }
        if (opt.inplace)
            file.Close();
        else {
            std::fprintf(stderr, "Saving MP4 stream...\n");
            MP4FileCopy copier(&file);
            copier.start(opt.dst);
            uint64_t count = copier.getTotalChunks();
            for (uint64_t i = 1; copier.copyNextChunk(); ++i) {
                std::fprintf(stderr, "\rWriting chunk %" PRId64 "/%" PRId64 "...",
                        i, count);
            }
        }
        std::fprintf(stderr, "\nOperation completed with no problem\n");
    } catch (mp4v2::impl::Exception *e) {
        handle_mp4error(e);
    }
}
Пример #6
0
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);
    }
}
Пример #7
0
size_t ALACSource::readSamples(void *buffer, size_t nsamples)
{
    nsamples = adjustSamplesToRead(nsamples);
    if (!nsamples) return 0;
    try {
	uint32_t bpf = m_format.bytesPerFrame();
	uint8_t *bufp = static_cast<uint8_t*>(buffer);
	uint32_t nread = 0;

	uint32_t size = std::min(m_buffer.rest(),
				 static_cast<uint32_t>(nsamples));
	if (size) {
	    std::memcpy(bufp, &m_buffer.v[m_buffer.done * bpf], size * bpf);
	    m_buffer.advance(size);
	    nread += size;
	    bufp += size * bpf;
	}
	while (nread < nsamples) {
	    MP4SampleId sid =
		m_file.GetSampleIdFromTime(m_track_id, m_position);
	    uint32_t size;
	    try {
		size = m_file.GetSampleSize(m_track_id, sid);
	    } catch (mp4v2::impl::Exception *e) {
		/*
		 * Come here when we try to read more samples beyond the end.
		 * This usually happens when stts entries are incorrect.
		 * We just treat this as EOF.
		 */
		delete e;
		break;
	    }
	    MP4Timestamp start;
	    MP4Duration duration;
	    std::vector<uint8_t> ivec(size);
	    uint8_t *vp = &ivec[0];

	    m_file.ReadSample(m_track_id, sid, &vp, &size, &start, &duration);
	    m_buffer.done = m_position - start;
	    m_position = start + duration;

	    BitBuffer bits;
	    BitBufferInit(&bits, &ivec[0], size);
	    m_buffer.v.resize(bpf * duration);
	    uint32_t ncount;
	    CHECKCA(m_decoder->Decode(&bits, &m_buffer.v[0], duration,
			m_format.m_nchannels, &ncount));
	    m_buffer.nsamples = ncount;

	    duration = std::min(ncount - m_buffer.done,
				static_cast<uint32_t>(nsamples) - nread);
	    std::memcpy(bufp, &m_buffer.v[m_buffer.done * bpf], duration * bpf);
	    m_buffer.advance(duration);
	    nread += duration;
	    bufp += duration * bpf;
	}
	addSamplesRead(nread);
	return nread;
    } catch (mp4v2::impl::Exception *e) {
	handle_mp4error(e);
    }
}