diff options
Diffstat (limited to 'contrib/ffmpeg/libavformat/flvenc.c')
-rw-r--r-- | contrib/ffmpeg/libavformat/flvenc.c | 144 |
1 files changed, 98 insertions, 46 deletions
diff --git a/contrib/ffmpeg/libavformat/flvenc.c b/contrib/ffmpeg/libavformat/flvenc.c index 0b09d9830..ece585d77 100644 --- a/contrib/ffmpeg/libavformat/flvenc.c +++ b/contrib/ffmpeg/libavformat/flvenc.c @@ -19,10 +19,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" +#include "flv.h" +#include "riff.h" #undef NDEBUG #include <assert.h> +static const AVCodecTag flv_video_codec_ids[] = { + {CODEC_ID_FLV1, FLV_CODECID_H263 }, + {CODEC_ID_FLASHSV, FLV_CODECID_SCREEN}, + {CODEC_ID_VP6F, FLV_CODECID_VP6 }, + {CODEC_ID_VP6, FLV_CODECID_VP6 }, + {CODEC_ID_NONE, 0} +}; + +static const AVCodecTag flv_audio_codec_ids[] = { + {CODEC_ID_MP3, FLV_CODECID_MP3 >> FLV_AUDIO_CODECID_OFFSET}, + {CODEC_ID_PCM_S8, FLV_CODECID_PCM_BE >> FLV_AUDIO_CODECID_OFFSET}, + {CODEC_ID_PCM_S16BE, FLV_CODECID_PCM_BE >> FLV_AUDIO_CODECID_OFFSET}, + {CODEC_ID_PCM_S16LE, FLV_CODECID_PCM_LE >> FLV_AUDIO_CODECID_OFFSET}, + {CODEC_ID_ADPCM_SWF, FLV_CODECID_ADPCM >> FLV_AUDIO_CODECID_OFFSET}, + {CODEC_ID_NONE, 0} +}; + typedef struct FLVContext { int hasAudio; int hasVideo; @@ -33,21 +52,21 @@ typedef struct FLVContext { } FLVContext; static int get_audio_flags(AVCodecContext *enc){ - int flags = (enc->bits_per_sample == 16) ? 0x2 : 0x0; + int flags = (enc->bits_per_sample == 16) ? FLV_SAMPLESSIZE_16BIT : FLV_SAMPLESSIZE_8BIT; switch (enc->sample_rate) { case 44100: - flags |= 0x0C; + flags |= FLV_SAMPLERATE_44100HZ; break; case 22050: - flags |= 0x08; + flags |= FLV_SAMPLERATE_22050HZ; break; case 11025: - flags |= 0x04; + flags |= FLV_SAMPLERATE_11025HZ; break; case 8000: //nellymoser only case 5512: //not mp3 - flags |= 0x00; + flags |= FLV_SAMPLERATE_SPECIAL; break; default: av_log(enc, AV_LOG_ERROR, "flv doesnt support that sample rate, choose from (44100, 22050, 11025)\n"); @@ -55,23 +74,24 @@ static int get_audio_flags(AVCodecContext *enc){ } if (enc->channels > 1) { - flags |= 0x01; + flags |= FLV_STEREO; } switch(enc->codec_id){ case CODEC_ID_MP3: - flags |= 0x20 | 0x2; + flags |= FLV_CODECID_MP3 | FLV_SAMPLESSIZE_16BIT; break; case CODEC_ID_PCM_S8: + flags |= FLV_CODECID_PCM_BE | FLV_SAMPLESSIZE_8BIT; break; case CODEC_ID_PCM_S16BE: - flags |= 0x2; + flags |= FLV_CODECID_PCM_BE | FLV_SAMPLESSIZE_16BIT; break; case CODEC_ID_PCM_S16LE: - flags |= 0x30 | 0x2; + flags |= FLV_CODECID_PCM_LE | FLV_SAMPLESSIZE_16BIT; break; case CODEC_ID_ADPCM_SWF: - flags |= 0x10; + flags |= FLV_CODECID_ADPCM | FLV_SAMPLESSIZE_16BIT; break; case 0: flags |= enc->codec_tag<<4; @@ -84,14 +104,6 @@ static int get_audio_flags(AVCodecContext *enc){ return flags; } -#define AMF_DOUBLE 0 -#define AMF_BOOLEAN 1 -#define AMF_STRING 2 -#define AMF_OBJECT 3 -#define AMF_MIXED_ARRAY 8 -#define AMF_ARRAY 10 -#define AMF_DATE 11 - static void put_amf_string(ByteIOContext *pb, const char *str) { size_t len = strlen(str); @@ -101,27 +113,26 @@ static void put_amf_string(ByteIOContext *pb, const char *str) static void put_amf_double(ByteIOContext *pb, double d) { - put_byte(pb, AMF_DOUBLE); + put_byte(pb, AMF_DATA_TYPE_NUMBER); put_be64(pb, av_dbl2int(d)); } +static void put_amf_bool(ByteIOContext *pb, int b) { + put_byte(pb, AMF_DATA_TYPE_BOOL); + put_byte(pb, !!b); +} + static int flv_write_header(AVFormatContext *s) { ByteIOContext *pb = &s->pb; FLVContext *flv = s->priv_data; - int i, width, height, samplerate; + int i, width, height, samplerate, samplesize, channels, audiocodecid, videocodecid; double framerate = 0.0; int metadata_size_pos, data_size; flv->hasAudio = 0; flv->hasVideo = 0; - put_tag(pb,"FLV"); - put_byte(pb,1); - put_byte(pb,0); // delayed write - put_be32(pb,9); - put_be32(pb,0); - for(i=0; i<s->nb_streams; i++){ AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_VIDEO) { @@ -133,12 +144,34 @@ static int flv_write_header(AVFormatContext *s) framerate = 1/av_q2d(s->streams[i]->codec->time_base); } flv->hasVideo=1; + + videocodecid = enc->codec_tag; + if(videocodecid == 0) { + av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n"); + return -1; + } } else { flv->hasAudio=1; samplerate = enc->sample_rate; + channels = enc->channels; + + audiocodecid = enc->codec_tag; + samplesize = (enc->codec_id == CODEC_ID_PCM_S8) ? 8 : 16; + + if(get_audio_flags(enc)<0) + return -1; } av_set_pts_info(s->streams[i], 24, 1, 1000); /* 24 bit pts in ms */ - if(enc->codec_tag == 5){ + } + put_tag(pb,"FLV"); + put_byte(pb,1); + put_byte(pb, FLV_HEADER_FLAG_HASAUDIO * flv->hasAudio + + FLV_HEADER_FLAG_HASVIDEO * flv->hasVideo); + put_be32(pb,9); + put_be32(pb,0); + + for(i=0; i<s->nb_streams; i++){ + if(s->streams[i]->codec->codec_tag == 5){ put_byte(pb,8); // message type put_be24(pb,0); // include flags put_be24(pb,0); // time stamp @@ -146,8 +179,6 @@ static int flv_write_header(AVFormatContext *s) put_be32(pb,11); // size flv->reserved=5; } - if(enc->codec_type == CODEC_TYPE_AUDIO && get_audio_flags(enc)<0) - return -1; } /* write meta_tag */ @@ -160,12 +191,12 @@ static int flv_write_header(AVFormatContext *s) /* now data of data_size size */ /* first event name as a string */ - put_byte(pb, AMF_STRING); // 1 byte + put_byte(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ - put_byte(pb, AMF_MIXED_ARRAY); - put_be32(pb, 4*flv->hasVideo + flv->hasAudio + 2); // +2 for duration and file size + put_byte(pb, AMF_DATA_TYPE_MIXEDARRAY); + put_be32(pb, 5*flv->hasVideo + 4*flv->hasAudio + 2); // +2 for duration and file size put_amf_string(pb, "duration"); flv->duration_offset= url_ftell(pb); @@ -183,11 +214,23 @@ static int flv_write_header(AVFormatContext *s) put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); + + put_amf_string(pb, "videocodecid"); + put_amf_double(pb, videocodecid); } if(flv->hasAudio){ put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, samplerate); + + put_amf_string(pb, "audiosamplesize"); + put_amf_double(pb, samplesize); + + put_amf_string(pb, "stereo"); + put_amf_bool(pb, (channels == 2)); + + put_amf_string(pb, "audiocodecid"); + put_amf_double(pb, audiocodecid); } put_amf_string(pb, "filesize"); @@ -195,7 +238,7 @@ static int flv_write_header(AVFormatContext *s) put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); - put_byte(pb, 9); // end marker 1 byte + put_byte(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size= url_ftell(pb) - metadata_size_pos - 10; @@ -210,16 +253,11 @@ static int flv_write_header(AVFormatContext *s) static int flv_write_trailer(AVFormatContext *s) { int64_t file_size; - int flags = 0; ByteIOContext *pb = &s->pb; FLVContext *flv = s->priv_data; file_size = url_ftell(pb); - flags |= flv->hasAudio ? 4 : 0; - flags |= flv->hasVideo ? 1 : 0; - url_fseek(pb, 4, SEEK_SET); - put_byte(pb,flags); /* update informations */ url_fseek(pb, flv->duration_offset, SEEK_SET); @@ -242,22 +280,35 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) // av_log(s, AV_LOG_DEBUG, "type:%d pts: %"PRId64" size:%d\n", enc->codec_type, timestamp, size); if (enc->codec_type == CODEC_TYPE_VIDEO) { - put_byte(pb, 9); - flags = 2; // choose h263 - flags |= pkt->flags & PKT_FLAG_KEY ? 0x10 : 0x20; // add keyframe indicator + put_byte(pb, FLV_TAG_TYPE_VIDEO); + + flags = enc->codec_tag; + if(flags == 0) { + av_log(enc, AV_LOG_ERROR, "video codec %X not compatible with flv\n",enc->codec_id); + return -1; + } + + flags |= pkt->flags & PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; } else { assert(enc->codec_type == CODEC_TYPE_AUDIO); flags = get_audio_flags(enc); assert(size); - put_byte(pb, 8); + put_byte(pb, FLV_TAG_TYPE_AUDIO); } - put_be24(pb,size+1); // include flags + if ((enc->codec_id == CODEC_ID_VP6) || (enc->codec_id == CODEC_ID_VP6F)) + put_be24(pb,size+2); // include the extra byte needed for VP6 in flv and flags + else + put_be24(pb,size+1); // include flags put_be24(pb,pkt->pts); put_be32(pb,flv->reserved); put_byte(pb,flags); + if (enc->codec_id == CODEC_ID_VP6) + put_byte(pb,0); + if (enc->codec_id == CODEC_ID_VP6F) + put_byte(pb, enc->extradata_size ? enc->extradata[0] : 0); put_buffer(pb, pkt->data, size); put_be32(pb,size+1+11); // previous tag size flv->duration = pkt->pts + pkt->duration; @@ -272,13 +323,14 @@ AVOutputFormat flv_muxer = { "video/x-flv", "flv", sizeof(FLVContext), -#ifdef CONFIG_MP3LAME +#ifdef CONFIG_LIBMP3LAME CODEC_ID_MP3, -#else // CONFIG_MP3LAME +#else // CONFIG_LIBMP3LAME CODEC_ID_NONE, -#endif // CONFIG_MP3LAME +#endif // CONFIG_LIBMP3LAME CODEC_ID_FLV1, flv_write_header, flv_write_packet, flv_write_trailer, + .codec_tag= (const AVCodecTag*[]){flv_video_codec_ids, flv_audio_codec_ids, 0}, }; |