00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "flv.h"
00023 #include "riff.h"
00024
00025 #undef NDEBUG
00026 #include <assert.h>
00027
00028 static const AVCodecTag flv_video_codec_ids[] = {
00029 {CODEC_ID_FLV1, FLV_CODECID_H263 },
00030 {CODEC_ID_FLASHSV, FLV_CODECID_SCREEN},
00031 {CODEC_ID_VP6F, FLV_CODECID_VP6 },
00032 {CODEC_ID_VP6, FLV_CODECID_VP6 },
00033 {CODEC_ID_NONE, 0}
00034 };
00035
00036 static const AVCodecTag flv_audio_codec_ids[] = {
00037 {CODEC_ID_MP3, FLV_CODECID_MP3 >> FLV_AUDIO_CODECID_OFFSET},
00038 {CODEC_ID_PCM_S8, FLV_CODECID_PCM_BE >> FLV_AUDIO_CODECID_OFFSET},
00039 {CODEC_ID_PCM_S16BE, FLV_CODECID_PCM_BE >> FLV_AUDIO_CODECID_OFFSET},
00040 {CODEC_ID_PCM_S16LE, FLV_CODECID_PCM_LE >> FLV_AUDIO_CODECID_OFFSET},
00041 {CODEC_ID_ADPCM_SWF, FLV_CODECID_ADPCM >> FLV_AUDIO_CODECID_OFFSET},
00042 {CODEC_ID_NONE, 0}
00043 };
00044
00045 typedef struct FLVContext {
00046 int hasAudio;
00047 int hasVideo;
00048 int reserved;
00049 offset_t duration_offset;
00050 offset_t filesize_offset;
00051 int64_t duration;
00052 } FLVContext;
00053
00054 static int get_audio_flags(AVCodecContext *enc){
00055 int flags = (enc->bits_per_sample == 16) ? FLV_SAMPLESSIZE_16BIT : FLV_SAMPLESSIZE_8BIT;
00056
00057 switch (enc->sample_rate) {
00058 case 44100:
00059 flags |= FLV_SAMPLERATE_44100HZ;
00060 break;
00061 case 22050:
00062 flags |= FLV_SAMPLERATE_22050HZ;
00063 break;
00064 case 11025:
00065 flags |= FLV_SAMPLERATE_11025HZ;
00066 break;
00067 case 8000:
00068 case 5512:
00069 if(enc->codec_id != CODEC_ID_MP3){
00070 flags |= FLV_SAMPLERATE_SPECIAL;
00071 break;
00072 }
00073 default:
00074 av_log(enc, AV_LOG_ERROR, "flv does not support that sample rate, choose from (44100, 22050, 11025).\n");
00075 return -1;
00076 }
00077
00078 if (enc->channels > 1) {
00079 flags |= FLV_STEREO;
00080 }
00081
00082 switch(enc->codec_id){
00083 case CODEC_ID_MP3:
00084 flags |= FLV_CODECID_MP3 | FLV_SAMPLESSIZE_16BIT;
00085 break;
00086 case CODEC_ID_PCM_S8:
00087 flags |= FLV_CODECID_PCM_BE | FLV_SAMPLESSIZE_8BIT;
00088 break;
00089 case CODEC_ID_PCM_S16BE:
00090 flags |= FLV_CODECID_PCM_BE | FLV_SAMPLESSIZE_16BIT;
00091 break;
00092 case CODEC_ID_PCM_S16LE:
00093 flags |= FLV_CODECID_PCM_LE | FLV_SAMPLESSIZE_16BIT;
00094 break;
00095 case CODEC_ID_ADPCM_SWF:
00096 flags |= FLV_CODECID_ADPCM | FLV_SAMPLESSIZE_16BIT;
00097 break;
00098 case 0:
00099 flags |= enc->codec_tag<<4;
00100 break;
00101 default:
00102 av_log(enc, AV_LOG_ERROR, "codec not compatible with flv\n");
00103 return -1;
00104 }
00105
00106 return flags;
00107 }
00108
00109 static void put_amf_string(ByteIOContext *pb, const char *str)
00110 {
00111 size_t len = strlen(str);
00112 put_be16(pb, len);
00113 put_buffer(pb, str, len);
00114 }
00115
00116 static void put_amf_double(ByteIOContext *pb, double d)
00117 {
00118 put_byte(pb, AMF_DATA_TYPE_NUMBER);
00119 put_be64(pb, av_dbl2int(d));
00120 }
00121
00122 static void put_amf_bool(ByteIOContext *pb, int b) {
00123 put_byte(pb, AMF_DATA_TYPE_BOOL);
00124 put_byte(pb, !!b);
00125 }
00126
00127 static int flv_write_header(AVFormatContext *s)
00128 {
00129 ByteIOContext *pb = s->pb;
00130 FLVContext *flv = s->priv_data;
00131 int i, width, height, samplerate, samplesize, channels, audiocodecid, videocodecid;
00132 double framerate = 0.0;
00133 int metadata_size_pos, data_size;
00134
00135 flv->hasAudio = 0;
00136 flv->hasVideo = 0;
00137
00138 for(i=0; i<s->nb_streams; i++){
00139 AVCodecContext *enc = s->streams[i]->codec;
00140 if (enc->codec_type == CODEC_TYPE_VIDEO) {
00141 width = enc->width;
00142 height = enc->height;
00143 if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) {
00144 framerate = av_q2d(s->streams[i]->r_frame_rate);
00145 } else {
00146 framerate = 1/av_q2d(s->streams[i]->codec->time_base);
00147 }
00148 flv->hasVideo=1;
00149
00150 videocodecid = enc->codec_tag;
00151 if(videocodecid == 0) {
00152 av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n");
00153 return -1;
00154 }
00155 } else {
00156 flv->hasAudio=1;
00157 samplerate = enc->sample_rate;
00158 channels = enc->channels;
00159
00160 audiocodecid = enc->codec_tag;
00161 samplesize = (enc->codec_id == CODEC_ID_PCM_S8) ? 8 : 16;
00162
00163 if(get_audio_flags(enc)<0)
00164 return -1;
00165 }
00166 av_set_pts_info(s->streams[i], 24, 1, 1000);
00167 }
00168 put_tag(pb,"FLV");
00169 put_byte(pb,1);
00170 put_byte(pb, FLV_HEADER_FLAG_HASAUDIO * flv->hasAudio
00171 + FLV_HEADER_FLAG_HASVIDEO * flv->hasVideo);
00172 put_be32(pb,9);
00173 put_be32(pb,0);
00174
00175 for(i=0; i<s->nb_streams; i++){
00176 if(s->streams[i]->codec->codec_tag == 5){
00177 put_byte(pb,8);
00178 put_be24(pb,0);
00179 put_be24(pb,0);
00180 put_be32(pb,0);
00181 put_be32(pb,11);
00182 flv->reserved=5;
00183 }
00184 }
00185
00186
00187 put_byte(pb, 18);
00188 metadata_size_pos= url_ftell(pb);
00189 put_be24(pb, 0);
00190 put_be24(pb, 0);
00191 put_be32(pb, 0);
00192
00193
00194
00195
00196 put_byte(pb, AMF_DATA_TYPE_STRING);
00197 put_amf_string(pb, "onMetaData");
00198
00199
00200 put_byte(pb, AMF_DATA_TYPE_MIXEDARRAY);
00201 put_be32(pb, 5*flv->hasVideo + 4*flv->hasAudio + 2);
00202
00203 put_amf_string(pb, "duration");
00204 flv->duration_offset= url_ftell(pb);
00205 put_amf_double(pb, 0);
00206
00207 if(flv->hasVideo){
00208 put_amf_string(pb, "width");
00209 put_amf_double(pb, width);
00210
00211 put_amf_string(pb, "height");
00212 put_amf_double(pb, height);
00213
00214 put_amf_string(pb, "videodatarate");
00215 put_amf_double(pb, s->bit_rate / 1024.0);
00216
00217 put_amf_string(pb, "framerate");
00218 put_amf_double(pb, framerate);
00219
00220 put_amf_string(pb, "videocodecid");
00221 put_amf_double(pb, videocodecid);
00222 }
00223
00224 if(flv->hasAudio){
00225 put_amf_string(pb, "audiosamplerate");
00226 put_amf_double(pb, samplerate);
00227
00228 put_amf_string(pb, "audiosamplesize");
00229 put_amf_double(pb, samplesize);
00230
00231 put_amf_string(pb, "stereo");
00232 put_amf_bool(pb, (channels == 2));
00233
00234 put_amf_string(pb, "audiocodecid");
00235 put_amf_double(pb, audiocodecid);
00236 }
00237
00238 put_amf_string(pb, "filesize");
00239 flv->filesize_offset= url_ftell(pb);
00240 put_amf_double(pb, 0);
00241
00242 put_amf_string(pb, "");
00243 put_byte(pb, AMF_END_OF_OBJECT);
00244
00245
00246 data_size= url_ftell(pb) - metadata_size_pos - 10;
00247 url_fseek(pb, metadata_size_pos, SEEK_SET);
00248 put_be24(pb, data_size);
00249 url_fseek(pb, data_size + 10 - 3, SEEK_CUR);
00250 put_be32(pb, data_size + 11);
00251
00252 return 0;
00253 }
00254
00255 static int flv_write_trailer(AVFormatContext *s)
00256 {
00257 int64_t file_size;
00258
00259 ByteIOContext *pb = s->pb;
00260 FLVContext *flv = s->priv_data;
00261
00262 file_size = url_ftell(pb);
00263
00264
00265 url_fseek(pb, flv->duration_offset, SEEK_SET);
00266 put_amf_double(pb, flv->duration / (double)1000);
00267 url_fseek(pb, flv->filesize_offset, SEEK_SET);
00268 put_amf_double(pb, file_size);
00269
00270 url_fseek(pb, file_size, SEEK_SET);
00271 return 0;
00272 }
00273
00274 static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
00275 {
00276 ByteIOContext *pb = s->pb;
00277 AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
00278 FLVContext *flv = s->priv_data;
00279 int size= pkt->size;
00280 int flags, flags_size;
00281
00282
00283
00284 if(enc->codec_id == CODEC_ID_VP6 || enc->codec_id == CODEC_ID_VP6F)
00285 flags_size= 2;
00286 else
00287 flags_size= 1;
00288
00289 if (enc->codec_type == CODEC_TYPE_VIDEO) {
00290 put_byte(pb, FLV_TAG_TYPE_VIDEO);
00291
00292 flags = enc->codec_tag;
00293 if(flags == 0) {
00294 av_log(enc, AV_LOG_ERROR, "video codec %X not compatible with flv\n",enc->codec_id);
00295 return -1;
00296 }
00297
00298 flags |= pkt->flags & PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER;
00299 } else {
00300 assert(enc->codec_type == CODEC_TYPE_AUDIO);
00301 flags = get_audio_flags(enc);
00302
00303 assert(size);
00304
00305 put_byte(pb, FLV_TAG_TYPE_AUDIO);
00306 }
00307
00308 put_be24(pb,size + flags_size);
00309 put_be24(pb,pkt->pts);
00310 put_byte(pb,pkt->pts >> 24);
00311 put_be24(pb,flv->reserved);
00312 put_byte(pb,flags);
00313 if (enc->codec_id == CODEC_ID_VP6)
00314 put_byte(pb,0);
00315 if (enc->codec_id == CODEC_ID_VP6F)
00316 put_byte(pb, enc->extradata_size ? enc->extradata[0] : 0);
00317 put_buffer(pb, pkt->data, size);
00318 put_be32(pb,size+flags_size+11);
00319 flv->duration = pkt->pts + pkt->duration;
00320
00321 put_flush_packet(pb);
00322 return 0;
00323 }
00324
00325 AVOutputFormat flv_muxer = {
00326 "flv",
00327 "flv format",
00328 "video/x-flv",
00329 "flv",
00330 sizeof(FLVContext),
00331 #ifdef CONFIG_LIBMP3LAME
00332 CODEC_ID_MP3,
00333 #else
00334 CODEC_ID_ADPCM_SWF,
00335 #endif
00336 CODEC_ID_FLV1,
00337 flv_write_header,
00338 flv_write_packet,
00339 flv_write_trailer,
00340 .codec_tag= (const AVCodecTag*[]){flv_video_codec_ids, flv_audio_codec_ids, 0},
00341 };