|
|
@ -29,13 +29,13 @@ |
|
|
|
#include "libavutil/mathematics.h" |
|
|
|
#include "libavutil/mathematics.h" |
|
|
|
#include "libavutil/opt.h" |
|
|
|
#include "libavutil/opt.h" |
|
|
|
#include "avformat.h" |
|
|
|
#include "avformat.h" |
|
|
|
#include "internal.h" |
|
|
|
#include "avio.h" |
|
|
|
#include "avio_internal.h" |
|
|
|
#include "avio_internal.h" |
|
|
|
|
|
|
|
#include "internal.h" |
|
|
|
|
|
|
|
#include "metadata.h" |
|
|
|
#include "pcm.h" |
|
|
|
#include "pcm.h" |
|
|
|
#include "riff.h" |
|
|
|
#include "riff.h" |
|
|
|
#include "w64.h" |
|
|
|
#include "w64.h" |
|
|
|
#include "avio.h" |
|
|
|
|
|
|
|
#include "metadata.h" |
|
|
|
|
|
|
|
#include "spdif.h" |
|
|
|
#include "spdif.h" |
|
|
|
|
|
|
|
|
|
|
|
typedef struct WAVDemuxContext { |
|
|
|
typedef struct WAVDemuxContext { |
|
|
@ -53,7 +53,6 @@ typedef struct WAVDemuxContext { |
|
|
|
int spdif; |
|
|
|
int spdif; |
|
|
|
} WAVDemuxContext; |
|
|
|
} WAVDemuxContext; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if CONFIG_WAV_DEMUXER |
|
|
|
#if CONFIG_WAV_DEMUXER |
|
|
|
|
|
|
|
|
|
|
|
static int64_t next_tag(AVIOContext *pb, uint32_t *tag) |
|
|
|
static int64_t next_tag(AVIOContext *pb, uint32_t *tag) |
|
|
@ -86,11 +85,9 @@ static int wav_probe(AVProbeData *p) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
if (!memcmp(p->buf + 8, "WAVE", 4)) { |
|
|
|
if (!memcmp(p->buf + 8, "WAVE", 4)) { |
|
|
|
if (!memcmp(p->buf, "RIFF", 4)) |
|
|
|
if (!memcmp(p->buf, "RIFF", 4)) |
|
|
|
/*
|
|
|
|
/* Since ACT demuxer has standard WAV header at top of it's
|
|
|
|
Since ACT demuxer has standard WAV header at top of it's own, |
|
|
|
* own, returning score is decreased to avoid probe conflict |
|
|
|
returning score is decreased to avoid probe conflict |
|
|
|
* between ACT and WAV. */ |
|
|
|
between ACT and WAV. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
return AVPROBE_SCORE_MAX - 1; |
|
|
|
return AVPROBE_SCORE_MAX - 1; |
|
|
|
else if (!memcmp(p->buf, "RF64", 4) && |
|
|
|
else if (!memcmp(p->buf, "RF64", 4) && |
|
|
|
!memcmp(p->buf + 12, "ds64", 4)) |
|
|
|
!memcmp(p->buf + 12, "ds64", 4)) |
|
|
@ -173,16 +170,22 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) |
|
|
|
|
|
|
|
|
|
|
|
if (umid_mask) { |
|
|
|
if (umid_mask) { |
|
|
|
/* the string formatting below is per SMPTE 330M-2004 Annex C */ |
|
|
|
/* the string formatting below is per SMPTE 330M-2004 Annex C */ |
|
|
|
if (umid_parts[4] == 0 && umid_parts[5] == 0 && umid_parts[6] == 0 && umid_parts[7] == 0) { |
|
|
|
if (umid_parts[4] == 0 && umid_parts[5] == 0 && |
|
|
|
|
|
|
|
umid_parts[6] == 0 && umid_parts[7] == 0) { |
|
|
|
/* basic UMID */ |
|
|
|
/* basic UMID */ |
|
|
|
snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, |
|
|
|
snprintf(temp, sizeof(temp), |
|
|
|
umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3]); |
|
|
|
"0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, |
|
|
|
|
|
|
|
umid_parts[0], umid_parts[1], |
|
|
|
|
|
|
|
umid_parts[2], umid_parts[3]); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
/* extended UMID */ |
|
|
|
/* extended UMID */ |
|
|
|
snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64 |
|
|
|
snprintf(temp, sizeof(temp), |
|
|
|
|
|
|
|
"0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64 |
|
|
|
"%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, |
|
|
|
"%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, |
|
|
|
umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3], |
|
|
|
umid_parts[0], umid_parts[1], |
|
|
|
umid_parts[4], umid_parts[5], umid_parts[6], umid_parts[7]); |
|
|
|
umid_parts[2], umid_parts[3], |
|
|
|
|
|
|
|
umid_parts[4], umid_parts[5], |
|
|
|
|
|
|
|
umid_parts[6], umid_parts[7]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ((ret = av_dict_set(&s->metadata, "umid", temp, 0)) < 0) |
|
|
|
if ((ret = av_dict_set(&s->metadata, "umid", temp, 0)) < 0) |
|
|
@ -197,7 +200,7 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) |
|
|
|
/* CodingHistory present */ |
|
|
|
/* CodingHistory present */ |
|
|
|
size -= 602; |
|
|
|
size -= 602; |
|
|
|
|
|
|
|
|
|
|
|
if (!(coding_history = av_malloc(size+1))) |
|
|
|
if (!(coding_history = av_malloc(size + 1))) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
|
|
if ((ret = avio_read(s->pb, coding_history, size)) < 0) |
|
|
|
if ((ret = avio_read(s->pb, coding_history, size)) < 0) |
|
|
@ -213,18 +216,18 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static const AVMetadataConv wav_metadata_conv[] = { |
|
|
|
static const AVMetadataConv wav_metadata_conv[] = { |
|
|
|
{"description", "comment" }, |
|
|
|
{ "description", "comment" }, |
|
|
|
{"originator", "encoded_by" }, |
|
|
|
{ "originator", "encoded_by" }, |
|
|
|
{"origination_date", "date" }, |
|
|
|
{ "origination_date", "date" }, |
|
|
|
{"origination_time", "creation_time"}, |
|
|
|
{ "origination_time", "creation_time" }, |
|
|
|
{0}, |
|
|
|
{ 0 }, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/* wav input */ |
|
|
|
/* wav input */ |
|
|
|
static int wav_read_header(AVFormatContext *s) |
|
|
|
static int wav_read_header(AVFormatContext *s) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int64_t size, av_uninit(data_size); |
|
|
|
int64_t size, av_uninit(data_size); |
|
|
|
int64_t sample_count=0; |
|
|
|
int64_t sample_count = 0; |
|
|
|
int rf64; |
|
|
|
int rf64; |
|
|
|
uint32_t tag; |
|
|
|
uint32_t tag; |
|
|
|
AVIOContext *pb = s->pb; |
|
|
|
AVIOContext *pb = s->pb; |
|
|
@ -253,8 +256,10 @@ static int wav_read_header(AVFormatContext *s) |
|
|
|
if (size < 24) |
|
|
|
if (size < 24) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
avio_rl64(pb); /* RIFF size */ |
|
|
|
avio_rl64(pb); /* RIFF size */ |
|
|
|
|
|
|
|
|
|
|
|
data_size = avio_rl64(pb); |
|
|
|
data_size = avio_rl64(pb); |
|
|
|
sample_count = avio_rl64(pb); |
|
|
|
sample_count = avio_rl64(pb); |
|
|
|
|
|
|
|
|
|
|
|
if (data_size < 0 || sample_count < 0) { |
|
|
|
if (data_size < 0 || sample_count < 0) { |
|
|
|
av_log(s, AV_LOG_ERROR, "negative data_size and/or sample_count in " |
|
|
|
av_log(s, AV_LOG_ERROR, "negative data_size and/or sample_count in " |
|
|
|
"ds64: data_size = %"PRId64", sample_count = %"PRId64"\n", |
|
|
|
"ds64: data_size = %"PRId64", sample_count = %"PRId64"\n", |
|
|
@ -285,7 +290,8 @@ static int wav_read_header(AVFormatContext *s) |
|
|
|
break; |
|
|
|
break; |
|
|
|
case MKTAG('d', 'a', 't', 'a'): |
|
|
|
case MKTAG('d', 'a', 't', 'a'): |
|
|
|
if (!got_fmt) { |
|
|
|
if (!got_fmt) { |
|
|
|
av_log(s, AV_LOG_ERROR, "found no 'fmt ' tag before the 'data' tag\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, |
|
|
|
|
|
|
|
"found no 'fmt ' tag before the 'data' tag\n"); |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -304,11 +310,11 @@ static int wav_read_header(AVFormatContext *s) |
|
|
|
if (!pb->seekable || (!rf64 && !size)) |
|
|
|
if (!pb->seekable || (!rf64 && !size)) |
|
|
|
goto break_loop; |
|
|
|
goto break_loop; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case MKTAG('f','a','c','t'): |
|
|
|
case MKTAG('f', 'a', 'c', 't'): |
|
|
|
if (!sample_count) |
|
|
|
if (!sample_count) |
|
|
|
sample_count = avio_rl32(pb); |
|
|
|
sample_count = avio_rl32(pb); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case MKTAG('b','e','x','t'): |
|
|
|
case MKTAG('b', 'e', 'x', 't'): |
|
|
|
if ((ret = wav_parse_bext_tag(s, size)) < 0) |
|
|
|
if ((ret = wav_parse_bext_tag(s, size)) < 0) |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
break; |
|
|
|
break; |
|
|
@ -363,6 +369,7 @@ static int wav_read_header(AVFormatContext *s) |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
break_loop: |
|
|
|
break_loop: |
|
|
|
if (data_ofs < 0) { |
|
|
|
if (data_ofs < 0) { |
|
|
|
av_log(s, AV_LOG_ERROR, "no 'data' tag found\n"); |
|
|
|
av_log(s, AV_LOG_ERROR, "no 'data' tag found\n"); |
|
|
@ -371,8 +378,11 @@ break_loop: |
|
|
|
|
|
|
|
|
|
|
|
avio_seek(pb, data_ofs, SEEK_SET); |
|
|
|
avio_seek(pb, data_ofs, SEEK_SET); |
|
|
|
|
|
|
|
|
|
|
|
if (!sample_count && st->codec->channels && av_get_bits_per_sample(st->codec->codec_id) && wav->data_end <= avio_size(pb)) |
|
|
|
if (!sample_count && st->codec->channels && |
|
|
|
sample_count = (data_size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); |
|
|
|
av_get_bits_per_sample(st->codec->codec_id) && wav->data_end <= avio_size(pb)) |
|
|
|
|
|
|
|
sample_count = (data_size << 3) / |
|
|
|
|
|
|
|
(st->codec->channels * |
|
|
|
|
|
|
|
(uint64_t)av_get_bits_per_sample(st->codec->codec_id)); |
|
|
|
if (sample_count) |
|
|
|
if (sample_count) |
|
|
|
st->duration = sample_count; |
|
|
|
st->duration = sample_count; |
|
|
|
|
|
|
|
|
|
|
@ -382,7 +392,8 @@ break_loop: |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Find chunk with w64 GUID by skipping over other chunks
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Find chunk with w64 GUID by skipping over other chunks. |
|
|
|
* @return the size of the found chunk |
|
|
|
* @return the size of the found chunk |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16]) |
|
|
|
static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16]) |
|
|
@ -404,8 +415,7 @@ static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16]) |
|
|
|
|
|
|
|
|
|
|
|
#define MAX_SIZE 4096 |
|
|
|
#define MAX_SIZE 4096 |
|
|
|
|
|
|
|
|
|
|
|
static int wav_read_packet(AVFormatContext *s, |
|
|
|
static int wav_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
AVPacket *pkt) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret, size; |
|
|
|
int ret, size; |
|
|
|
int64_t left; |
|
|
|
int64_t left; |
|
|
@ -470,8 +480,8 @@ smv_out: |
|
|
|
|
|
|
|
|
|
|
|
left = wav->data_end - avio_tell(s->pb); |
|
|
|
left = wav->data_end - avio_tell(s->pb); |
|
|
|
if (wav->ignore_length) |
|
|
|
if (wav->ignore_length) |
|
|
|
left= INT_MAX; |
|
|
|
left = INT_MAX; |
|
|
|
if (left <= 0){ |
|
|
|
if (left <= 0) { |
|
|
|
if (CONFIG_W64_DEMUXER && wav->w64) |
|
|
|
if (CONFIG_W64_DEMUXER && wav->w64) |
|
|
|
left = find_guid(s->pb, ff_w64_guid_data) - 24; |
|
|
|
left = find_guid(s->pb, ff_w64_guid_data) - 24; |
|
|
|
else |
|
|
|
else |
|
|
@ -482,7 +492,7 @@ smv_out: |
|
|
|
goto smv_retry; |
|
|
|
goto smv_retry; |
|
|
|
return AVERROR_EOF; |
|
|
|
return AVERROR_EOF; |
|
|
|
} |
|
|
|
} |
|
|
|
wav->data_end= avio_tell(s->pb) + left; |
|
|
|
wav->data_end = avio_tell(s->pb) + left; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
size = MAX_SIZE; |
|
|
|
size = MAX_SIZE; |
|
|
@ -552,12 +562,11 @@ AVInputFormat ff_wav_demuxer = { |
|
|
|
.read_packet = wav_read_packet, |
|
|
|
.read_packet = wav_read_packet, |
|
|
|
.read_seek = wav_read_seek, |
|
|
|
.read_seek = wav_read_seek, |
|
|
|
.flags = AVFMT_GENERIC_INDEX, |
|
|
|
.flags = AVFMT_GENERIC_INDEX, |
|
|
|
.codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 }, |
|
|
|
.codec_tag = (const AVCodecTag * const []) { ff_codec_wav_tags, 0 }, |
|
|
|
.priv_class = &wav_demuxer_class, |
|
|
|
.priv_class = &wav_demuxer_class, |
|
|
|
}; |
|
|
|
}; |
|
|
|
#endif /* CONFIG_WAV_DEMUXER */ |
|
|
|
#endif /* CONFIG_WAV_DEMUXER */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if CONFIG_W64_DEMUXER |
|
|
|
#if CONFIG_W64_DEMUXER |
|
|
|
static int w64_probe(AVProbeData *p) |
|
|
|
static int w64_probe(AVProbeData *p) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -583,7 +592,8 @@ static int w64_read_header(AVFormatContext *s) |
|
|
|
if (memcmp(guid, ff_w64_guid_riff, 16)) |
|
|
|
if (memcmp(guid, ff_w64_guid_riff, 16)) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
|
if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8) /* riff + wave + fmt + sizes */ |
|
|
|
/* riff + wave + fmt + sizes */ |
|
|
|
|
|
|
|
if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
|
avio_read(pb, guid, 16); |
|
|
|
avio_read(pb, guid, 16); |
|
|
@ -685,6 +695,6 @@ AVInputFormat ff_w64_demuxer = { |
|
|
|
.read_packet = wav_read_packet, |
|
|
|
.read_packet = wav_read_packet, |
|
|
|
.read_seek = wav_read_seek, |
|
|
|
.read_seek = wav_read_seek, |
|
|
|
.flags = AVFMT_GENERIC_INDEX, |
|
|
|
.flags = AVFMT_GENERIC_INDEX, |
|
|
|
.codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 }, |
|
|
|
.codec_tag = (const AVCodecTag * const []) { ff_codec_wav_tags, 0 }, |
|
|
|
}; |
|
|
|
}; |
|
|
|
#endif /* CONFIG_W64_DEMUXER */ |
|
|
|
#endif /* CONFIG_W64_DEMUXER */ |
|
|
|