X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FWav.cpp;h=2ffadd404cecc360a8f5827db0e73d87b46ada14;hb=260692554632887d4e978775001081add386b909;hp=92bd5e7306d241f64aef5085507c1dc8c751afc9;hpb=bfedf725dac9d13f3a02fe69f45c302ab29d2b1e;p=asdcplib.git diff --git a/src/Wav.cpp b/src/Wav.cpp index 92bd5e7..2ffadd4 100755 --- a/src/Wav.cpp +++ b/src/Wav.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2006, John Hurst +Copyright (c) 2005-2018, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -44,8 +44,8 @@ ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADes nchannels = ADesc.ChannelCount; bitspersample = ADesc.QuantizationBits; samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient()); - avgbps = samplespersec * nchannels * ((bitspersample + 7) / 8); blockalign = nchannels * ((bitspersample + 7) / 8); + avgbps = samplespersec * blockalign; cbsize = 0; data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration; } @@ -54,7 +54,7 @@ ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADes void ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const { - ADesc.SampleRate = PictureRate; + ADesc.EditRate = PictureRate; ADesc.LinkedTrackID = 0; ADesc.Locked = 0; @@ -65,6 +65,7 @@ ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDC ADesc.QuantizationBits = bitspersample; ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc); ADesc.ContainerDuration = data_len / FrameBufferSize; + ADesc.ChannelFormat = PCM::CF_NONE; } @@ -137,7 +138,7 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, fourcc test_RIFF(p); p += 4; if ( test_RIFF != FCC_RIFF ) { - DefaultLogSink().Error("File does not begin with RIFF header\n"); + // DefaultLogSink().Debug("File does not begin with RIFF header\n"); return RESULT_RAW_FORMAT; } @@ -146,7 +147,7 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, fourcc test_WAVE(p); p += 4; if ( test_WAVE != FCC_WAVE ) { - DefaultLogSink().Error("File does not contain a WAVE header\n"); + DefaultLogSink().Debug("File does not contain a WAVE header\n"); return RESULT_RAW_FORMAT; } @@ -161,7 +162,7 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, { if ( chunk_size > RIFF_len ) { - DefaultLogSink().Error("Chunk size %lu larger than file: %lu\n", chunk_size, RIFF_len); + DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len); return RESULT_RAW_FORMAT; } @@ -174,9 +175,9 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, { ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2; - if ( format != 1 ) + if ( format != ASDCP_WAVE_FORMAT_PCM && format != ASDCP_WAVE_FORMAT_EXTENSIBLE ) { - DefaultLogSink().Error("Expecting uncompressed essence, got format type %hu\n", format); + DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format); return RESULT_RAW_FORMAT; } @@ -185,7 +186,7 @@ ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, avgbps = KM_i32_LE(*(ui32_t*)p); p += 4; blockalign = KM_i16_LE(*(ui16_t*)p); p += 2; bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2; - p += chunk_size - 16; + p += chunk_size - 16; // 16 is the number of bytes read in this block } else { @@ -259,15 +260,16 @@ extended_to_Rat(const byte_t* buf) void ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const { - ADesc.SampleRate = PictureRate; + ADesc.EditRate = PictureRate; ADesc.ChannelCount = numChannels; ADesc.AudioSamplingRate = extended_to_Rat(sampleRate); ADesc.QuantizationBits = sampleSize; ADesc.BlockAlign = sampleSize / 8; - ADesc.AvgBps = ADesc.BlockAlign * (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient()); + ADesc.AvgBps = (ui32_t) (ADesc.BlockAlign * ADesc.AudioSamplingRate.Quotient()); ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc); ADesc.ContainerDuration = data_len / FrameBufferSize; + ADesc.ChannelFormat = PCM::CF_NONE; } // @@ -303,7 +305,7 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, fourcc test_FORM(p); p += 4; if ( test_FORM != FCC_FORM ) { - DefaultLogSink().Error("File does not begin with FORM header\n"); + // DefaultLogSink().Debug("File does not begin with FORM header\n"); return RESULT_RAW_FORMAT; } @@ -312,7 +314,7 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, fourcc test_AIFF(p); p += 4; if ( test_AIFF != FCC_AIFF ) { - DefaultLogSink().Error("File does not contain an AIFF header\n"); + DefaultLogSink().Debug("File does not contain an AIFF header\n"); return RESULT_RAW_FORMAT; } @@ -335,7 +337,7 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, { if ( chunk_size > RIFF_len ) { - DefaultLogSink().Error("Chunk size %lu larger than file: %lu\n", chunk_size, RIFF_len); + DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len); return RESULT_RAW_FORMAT; } @@ -344,7 +346,6 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, data_len = chunk_size - 8; *data_start = (p - buf) + offset; - fprintf(stderr, "*data_start: %p\n", *data_start); break; } else @@ -362,7 +363,237 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, return RESULT_OK; } +ASDCP::RF64::SimpleRF64Header::SimpleRF64Header(ASDCP::PCM::AudioDescriptor& ADesc) +{ + format = 1; + nchannels = ADesc.ChannelCount; + bitspersample = ADesc.QuantizationBits; + samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient()); + blockalign = nchannels * ((bitspersample + 7) / 8); + avgbps = samplespersec * blockalign; + cbsize = 0; + data_len = static_cast(ASDCP::PCM::CalcFrameBufferSize(ADesc)) * ADesc.ContainerDuration; +} + +// +void +ASDCP::RF64::SimpleRF64Header::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const +{ + ADesc.EditRate = PictureRate; + + ADesc.LinkedTrackID = 0; + ADesc.Locked = 0; + ADesc.ChannelCount = nchannels; + ADesc.AudioSamplingRate = Rational(samplespersec, 1); + ADesc.AvgBps = avgbps; + ADesc.BlockAlign = blockalign; + ADesc.QuantizationBits = bitspersample; + ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc); + ADesc.ContainerDuration = data_len / FrameBufferSize; + ADesc.ChannelFormat = PCM::CF_NONE; +} + +// +ASDCP::Result_t +ASDCP::RF64::SimpleRF64Header::WriteToFile(Kumu::FileWriter& OutFile) const +{ + static ui32_t fmt_len = + sizeof(format) + + sizeof(nchannels) + + sizeof(samplespersec) + + sizeof(avgbps) + + sizeof(blockalign) + + sizeof(bitspersample) + + sizeof(cbsize); + + ui32_t write_count = 0; + ui64_t RIFF_len = data_len + SimpleWavHeaderLength - 8; + // DefaultLogSink().Debug("RIFF_len is %llu.\n", RIFF_len); + byte_t* tmp_header = NULL; + ui32_t header_len = 0; + + if (RIFF_len > MAX_RIFF_LEN) + { + DefaultLogSink().Debug("Will write out an RF64 wave file.\n"); + ui32_t data32_len = ((data_len < MAX_RIFF_LEN) ? data_len : MAX_RIFF_LEN); + ui64_t data64_len = ((data_len < MAX_RIFF_LEN) ? 0 : data_len); + static ui32_t ds64_len = + sizeof(RIFF_len) + + sizeof(data64_len) + + sizeof(SAMPLE_COUNT) + + sizeof(TABLE_LEN); + + header_len = SIMPLE_RF64_HEADER_LEN; + tmp_header = new byte_t[header_len]; + byte_t* p = tmp_header; + memcpy(p, &FCC_RF64, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(MAX_RIFF_LEN); p += 4; + memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4; + memcpy(p, &FCC_ds64, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(ds64_len); p += 4; + *((ui64_t*)p) = KM_i64_LE(RIFF_len); p += 8; + *((ui64_t*)p) = KM_i64_LE(data64_len); p += 8; + *((ui64_t*)p) = KM_i64_LE(SAMPLE_COUNT); p += 8; + *((ui32_t*)p) = KM_i32_LE(TABLE_LEN); p += 4; + memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4; + *((ui16_t*)p) = KM_i16_LE(format); p += 2; + *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2; + *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4; + *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4; + *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2; + *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2; + *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2; + memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(data32_len); p += 4; + write_count = (p - tmp_header); + } + else + { + DefaultLogSink().Debug("Will write out a regular wave file.\n"); + header_len = SimpleWavHeaderLength; + tmp_header = new byte_t[header_len]; + byte_t* p = tmp_header; + memcpy(p, &Wav::FCC_RIFF, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4; + memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4; + memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4; + *((ui16_t*)p) = KM_i16_LE(format); p += 2; + *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2; + *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4; + *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4; + *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2; + *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2; + *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2; + memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(data_len); p += 4; + write_count = (p - tmp_header); + } + if (header_len != write_count) + { + DefaultLogSink().Warn("Expected to write %u bytes but wrote %u bytes for header.\n", + header_len, write_count); + } + write_count = 0; + ASDCP::Result_t r = OutFile.Write(tmp_header, header_len, &write_count); + delete [] tmp_header; + return r; +} + +// +ASDCP::Result_t +ASDCP::RF64::SimpleRF64Header::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start) +{ + ui32_t read_count = 0; + ui32_t local_data_start = 0; + ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader); + + if ( data_start == 0 ) + data_start = &local_data_start; + + Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count); + + if ( ASDCP_SUCCESS(result) ) + result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start); + else + DefaultLogSink().Error("Failed to read %d bytes from file\n", Wav::MaxWavHeader); + + return result; +} + +ASDCP::Result_t +ASDCP::RF64::SimpleRF64Header::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start) +{ + if ( buf_len < SIMPLE_RF64_HEADER_LEN ) + return RESULT_SMALLBUF; + + *data_start = 0; + const byte_t* p = buf; + const byte_t* end_p = p + buf_len; + + fourcc test_RF64(p); p += 4; + if ( test_RF64 != FCC_RF64 ) + { + DefaultLogSink().Debug("File does not begin with RF64 header\n"); + return RESULT_RAW_FORMAT; + } + + ui32_t tmp_len = KM_i32_LE(*(ui32_t*)p); p += 4; + + fourcc test_WAVE(p); p += 4; + if ( test_WAVE != Wav::FCC_WAVE ) + { + DefaultLogSink().Debug("File does not contain a WAVE header\n"); + return RESULT_RAW_FORMAT; + } + + fourcc test_ds64(p); p += 4; + if ( test_ds64 != FCC_ds64 ) + { + DefaultLogSink().Debug("File does not contain a ds64 chunk\n"); + return RESULT_RAW_FORMAT; + } + ui32_t ds64_len = KM_i32_LE(*(ui32_t*)p); p += 4; + ui64_t RIFF_len = ((tmp_len == MAX_RIFF_LEN) ? KM_i64_LE(*(ui64_t*)p) : tmp_len); p += 8; + data_len = KM_i64_LE(*(ui64_t*)p); p += 8; + p += (ds64_len - 16); // skip rest of ds64 chunk + + fourcc test_fcc; + + while ( p < end_p ) + { + test_fcc = fourcc(p); p += 4; + ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4; + + if ( test_fcc == Wav::FCC_data ) + { + if ( chunk_size != MAX_RIFF_LEN ) + { + if ( chunk_size > RIFF_len ) + { + DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len); + return RESULT_RAW_FORMAT; + } + + data_len = chunk_size; + } + + *data_start = p - buf; + break; + } + + if ( test_fcc == Wav::FCC_fmt_ ) + { + ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2; + + if ( format != Wav::ASDCP_WAVE_FORMAT_PCM && format != Wav::ASDCP_WAVE_FORMAT_EXTENSIBLE ) + { + DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format); + return RESULT_RAW_FORMAT; + } + + nchannels = KM_i16_LE(*(ui16_t*)p); p += 2; + samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4; + avgbps = KM_i32_LE(*(ui32_t*)p); p += 4; + blockalign = KM_i16_LE(*(ui16_t*)p); p += 2; + bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2; + p += chunk_size - 16; // 16 is the number of bytes read in this block + } + else + { + p += chunk_size; + } + } + if ( *data_start == 0 ) // can't have no data! + { + DefaultLogSink().Error("No data chunk found, file contains no essence\n"); + return RESULT_RAW_FORMAT; + } + + return RESULT_OK; +} // // end Wav.cpp