00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/intreadwrite.h"
00023 #include "avformat.h"
00024 #include "internal.h"
00025 #include "avio_internal.h"
00026 #include "apetag.h"
00027
00028 #define WV_EXTRA_SIZE 12
00029 #define WV_END_BLOCK 0x1000
00030
00031 typedef struct{
00032 uint32_t duration;
00033 } WVMuxContext;
00034
00035 static int write_header(AVFormatContext *s)
00036 {
00037 AVCodecContext *codec = s->streams[0]->codec;
00038
00039 if (s->nb_streams > 1) {
00040 av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
00041 return AVERROR(EINVAL);
00042 }
00043 if (codec->codec_id != AV_CODEC_ID_WAVPACK) {
00044 av_log(s, AV_LOG_ERROR, "unsupported codec\n");
00045 return AVERROR(EINVAL);
00046 }
00047 if (codec->extradata_size > 0) {
00048 av_log_missing_feature(s, "remuxing from matroska container", 0);
00049 return AVERROR_PATCHWELCOME;
00050 }
00051 avpriv_set_pts_info(s->streams[0], 64, 1, codec->sample_rate);
00052
00053 return 0;
00054 }
00055
00056 static int write_packet(AVFormatContext *s, AVPacket *pkt)
00057 {
00058 WVMuxContext *wc = s->priv_data;
00059 AVCodecContext *codec = s->streams[0]->codec;
00060 AVIOContext *pb = s->pb;
00061 uint64_t size;
00062 uint32_t flags;
00063 uint32_t left = pkt->size;
00064 uint8_t *ptr = pkt->data;
00065 int off = codec->channels > 2 ? 4 : 0;
00066
00067
00068
00069 wc->duration += pkt->duration;
00070 ffio_wfourcc(pb, "wvpk");
00071 if (off) {
00072 size = AV_RL32(pkt->data);
00073 if (size <= 12)
00074 return AVERROR_INVALIDDATA;
00075 size -= 12;
00076 } else {
00077 size = pkt->size;
00078 }
00079
00080 if (size + off > left)
00081 return AVERROR_INVALIDDATA;
00082
00083 avio_wl32(pb, size + 12);
00084 avio_wl16(pb, 0x410);
00085 avio_w8(pb, 0);
00086 avio_w8(pb, 0);
00087 avio_wl32(pb, -1);
00088 avio_wl32(pb, pkt->pts);
00089 ptr += off; left -= off;
00090 flags = AV_RL32(ptr + 4);
00091 avio_write(pb, ptr, size);
00092 ptr += size; left -= size;
00093
00094 while (!(flags & WV_END_BLOCK) &&
00095 (left >= 4 + WV_EXTRA_SIZE)) {
00096 ffio_wfourcc(pb, "wvpk");
00097 size = AV_RL32(ptr);
00098 ptr += 4; left -= 4;
00099 if (size < 24 || size - 24 > left)
00100 return AVERROR_INVALIDDATA;
00101 avio_wl32(pb, size);
00102 avio_wl16(pb, 0x410);
00103 avio_w8(pb, 0);
00104 avio_w8(pb, 0);
00105 avio_wl32(pb, -1);
00106 avio_wl32(pb, pkt->pts);
00107 flags = AV_RL32(ptr + 4);
00108 avio_write(pb, ptr, WV_EXTRA_SIZE);
00109 ptr += WV_EXTRA_SIZE; left -= WV_EXTRA_SIZE;
00110 avio_write(pb, ptr, size - 24);
00111 ptr += size - 24; left -= size - 24;
00112 }
00113 avio_flush(pb);
00114
00115 return 0;
00116 }
00117
00118 static int write_trailer(AVFormatContext *s)
00119 {
00120 WVMuxContext *wc = s->priv_data;
00121 AVIOContext *pb = s->pb;
00122
00123 ff_ape_write(s);
00124
00125 if (pb->seekable) {
00126 avio_seek(pb, 12, SEEK_SET);
00127 avio_wl32(pb, wc->duration);
00128 avio_flush(pb);
00129 }
00130
00131 return 0;
00132 }
00133
00134 AVOutputFormat ff_wv_muxer = {
00135 .name = "wv",
00136 .long_name = NULL_IF_CONFIG_SMALL("WavPack"),
00137 .priv_data_size = sizeof(WVMuxContext),
00138 .extensions = "wv",
00139 .audio_codec = AV_CODEC_ID_WAVPACK,
00140 .video_codec = AV_CODEC_ID_NONE,
00141 .write_header = write_header,
00142 .write_packet = write_packet,
00143 .write_trailer = write_trailer,
00144 };