00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 #include "voc.h"
00023 #include "internal.h"
00024 
00025 
00026 typedef struct voc_enc_context {
00027     int param_written;
00028 } VocEncContext;
00029 
00030 static int voc_write_header(AVFormatContext *s)
00031 {
00032     AVIOContext *pb = s->pb;
00033     const int header_size = 26;
00034     const int version = 0x0114;
00035 
00036     if (s->nb_streams != 1
00037         || s->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
00038         return AVERROR_PATCHWELCOME;
00039 
00040     avio_write(pb, ff_voc_magic, sizeof(ff_voc_magic) - 1);
00041     avio_wl16(pb, header_size);
00042     avio_wl16(pb, version);
00043     avio_wl16(pb, ~version + 0x1234);
00044 
00045     return 0;
00046 }
00047 
00048 static int voc_write_packet(AVFormatContext *s, AVPacket *pkt)
00049 {
00050     VocEncContext *voc = s->priv_data;
00051     AVCodecContext *enc = s->streams[0]->codec;
00052     AVIOContext *pb = s->pb;
00053 
00054     if (!voc->param_written) {
00055         if (enc->codec_tag > 0xFF) {
00056             avio_w8(pb, VOC_TYPE_NEW_VOICE_DATA);
00057             avio_wl24(pb, pkt->size + 12);
00058             avio_wl32(pb, enc->sample_rate);
00059             avio_w8(pb, enc->bits_per_coded_sample);
00060             avio_w8(pb, enc->channels);
00061             avio_wl16(pb, enc->codec_tag);
00062             avio_wl32(pb, 0);
00063         } else {
00064             if (s->streams[0]->codec->channels > 1) {
00065                 avio_w8(pb, VOC_TYPE_EXTENDED);
00066                 avio_wl24(pb, 4);
00067                 avio_wl16(pb, 65536-256000000/(enc->sample_rate*enc->channels));
00068                 avio_w8(pb, enc->codec_tag);
00069                 avio_w8(pb, enc->channels - 1);
00070             }
00071             avio_w8(pb, VOC_TYPE_VOICE_DATA);
00072             avio_wl24(pb, pkt->size + 2);
00073             avio_w8(pb, 256 - 1000000 / enc->sample_rate);
00074             avio_w8(pb, enc->codec_tag);
00075         }
00076         voc->param_written = 1;
00077     } else {
00078         avio_w8(pb, VOC_TYPE_VOICE_DATA_CONT);
00079         avio_wl24(pb, pkt->size);
00080     }
00081 
00082     avio_write(pb, pkt->data, pkt->size);
00083     return 0;
00084 }
00085 
00086 static int voc_write_trailer(AVFormatContext *s)
00087 {
00088     avio_w8(s->pb, 0);
00089     return 0;
00090 }
00091 
00092 AVOutputFormat ff_voc_muxer = {
00093     "voc",
00094     NULL_IF_CONFIG_SMALL("Creative Voice file format"),
00095     "audio/x-voc",
00096     "voc",
00097     sizeof(VocEncContext),
00098     CODEC_ID_PCM_U8,
00099     CODEC_ID_NONE,
00100     voc_write_header,
00101     voc_write_packet,
00102     voc_write_trailer,
00103     .codec_tag=(const AVCodecTag* const []){ff_voc_codec_tags, 0},
00104 };