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 AVCodecContext *enc = s->streams[0]->codec;
00034 const int header_size = 26;
00035 const int version = 0x0114;
00036
00037 if (s->nb_streams != 1
00038 || s->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
00039 return AVERROR_PATCHWELCOME;
00040
00041 if (!enc->codec_tag && enc->codec_id != AV_CODEC_ID_PCM_U8) {
00042 av_log(s, AV_LOG_ERROR, "unsupported codec\n");
00043 return AVERROR(EINVAL);
00044 }
00045
00046 avio_write(pb, ff_voc_magic, sizeof(ff_voc_magic) - 1);
00047 avio_wl16(pb, header_size);
00048 avio_wl16(pb, version);
00049 avio_wl16(pb, ~version + 0x1234);
00050
00051 return 0;
00052 }
00053
00054 static int voc_write_packet(AVFormatContext *s, AVPacket *pkt)
00055 {
00056 VocEncContext *voc = s->priv_data;
00057 AVCodecContext *enc = s->streams[0]->codec;
00058 AVIOContext *pb = s->pb;
00059
00060 if (!voc->param_written) {
00061 if (enc->codec_tag > 3) {
00062 avio_w8(pb, VOC_TYPE_NEW_VOICE_DATA);
00063 avio_wl24(pb, pkt->size + 12);
00064 avio_wl32(pb, enc->sample_rate);
00065 avio_w8(pb, enc->bits_per_coded_sample);
00066 avio_w8(pb, enc->channels);
00067 avio_wl16(pb, enc->codec_tag);
00068 avio_wl32(pb, 0);
00069 } else {
00070 if (s->streams[0]->codec->channels > 1) {
00071 avio_w8(pb, VOC_TYPE_EXTENDED);
00072 avio_wl24(pb, 4);
00073 avio_wl16(pb, 65536-(256000000 + enc->sample_rate*enc->channels/2)/(enc->sample_rate*enc->channels));
00074 avio_w8(pb, enc->codec_tag);
00075 avio_w8(pb, enc->channels - 1);
00076 }
00077 avio_w8(pb, VOC_TYPE_VOICE_DATA);
00078 avio_wl24(pb, pkt->size + 2);
00079 avio_w8(pb, 256 - (1000000 + enc->sample_rate/2) / enc->sample_rate);
00080 avio_w8(pb, enc->codec_tag);
00081 }
00082 voc->param_written = 1;
00083 } else {
00084 avio_w8(pb, VOC_TYPE_VOICE_DATA_CONT);
00085 avio_wl24(pb, pkt->size);
00086 }
00087
00088 avio_write(pb, pkt->data, pkt->size);
00089 return 0;
00090 }
00091
00092 static int voc_write_trailer(AVFormatContext *s)
00093 {
00094 avio_w8(s->pb, 0);
00095 return 0;
00096 }
00097
00098 AVOutputFormat ff_voc_muxer = {
00099 .name = "voc",
00100 .long_name = NULL_IF_CONFIG_SMALL("Creative Voice"),
00101 .mime_type = "audio/x-voc",
00102 .extensions = "voc",
00103 .priv_data_size = sizeof(VocEncContext),
00104 .audio_codec = AV_CODEC_ID_PCM_S16LE,
00105 .video_codec = AV_CODEC_ID_NONE,
00106 .write_header = voc_write_header,
00107 .write_packet = voc_write_packet,
00108 .write_trailer = voc_write_trailer,
00109 .codec_tag = (const AVCodecTag* const []){ ff_voc_codec_tags, 0 },
00110 };