分类: C/C++
2012-05-02 17:17:31
static int flv_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
FLVContext *flv = (FLVContext*)s->priv_data;
AVCodecContext *audio_enc = NULL, *video_enc = NULL;
int i, metadata_count = 0;
double framerate = 0.0;
int64_t metadata_size_pos, data_size, metadata_count_pos;
AVDictionaryEntry *tag = NULL;
for(i=0; i
AVCodecContext *enc = s->streams[i]->codec;
FLVStreamContext *sc;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) {
framerate = av_q2d(s->streams[i]->r_frame_rate);
} else {
framerate = 1 / (av_q2d(s->streams[i]->codec->time_base) * s->streams[i]->codec->ticks_per_frame);
}
video_enc = enc;
if(enc->codec_tag == 0) {
av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n");
return -1;
}
} else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_enc = enc;
if(get_audio_flags(enc)<0)
return -1;
}
avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */
sc = (FLVStreamContext*)av_mallocz(sizeof(FLVStreamContext));
if (!sc)
return AVERROR(ENOMEM);
s->streams[i]->priv_data = sc;
sc->last_ts = -1;
}
flv->delay = AV_NOPTS_VALUE;
avio_write(pb, (const unsigned char*)"FLV", 3);
avio_w8(pb,1);
avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!audio_enc
+ FLV_HEADER_FLAG_HASVIDEO * !!video_enc);
avio_wb32(pb,9);
avio_wb32(pb,0);
for(i=0; i
if(s->streams[i]->codec->codec_tag == 5){
avio_w8(pb,8); // message type
avio_wb24(pb,0); // include flags
avio_wb24(pb,0); // time stamp
avio_wb32(pb,0); // reserved
avio_wb32(pb,11); // size
flv->reserved=5;
}
}
/* write meta_tag */
avio_w8(pb, 18); // tag type META
metadata_size_pos = avio_tell(pb);
avio_wb24(pb, 0); // size of data part (sum of all parts below)
avio_wb24(pb, 0); // time stamp
avio_wb32(pb, 0); // reserved
/* now data of data_size size */
/* first event name as a string */
avio_w8(pb, AMF_DATA_TYPE_STRING);
put_amf_string(pb, "onMetaData"); // 12 bytes
/* mixed array (hash) with size and string/type/data tuples */
avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
metadata_count_pos = avio_tell(pb);
metadata_count = 7 + 6*!!video_enc + 6*!!audio_enc + 1 + 4; // +2 for duration and file size
avio_wb32(pb, metadata_count);
/********** Add KeyFrame Index ***********************************/
put_amf_string(pb, "hasKeyframes");
put_amf_bool(pb, true);
put_amf_string(pb, "hasVideo");
put_amf_bool(pb, !!video_enc);
put_amf_string(pb, "hasAudio");
put_amf_bool(pb, !!audio_enc);
put_amf_string(pb, "hasMetadata");
put_amf_bool(pb, true);
put_amf_string(pb, "canSeekToEnd");
put_amf_bool(pb, false);
/************************************************************************/
put_amf_string(pb, "duration");
flv->duration_offset = avio_tell(pb);
put_amf_double(pb, s->duration / AV_TIME_BASE); // fill in the guessed duration, it'll be corrected later if incorrect
/********** Add KeyFrame Index ***********************************/
put_amf_string(pb, "datasize");
flv->datasize_offset = avio_tell(pb);
flv->datasize = 0;
put_amf_double(pb, 0); // delayed write
/************************************************************************/
if(video_enc)
{
/********** Add KeyFrame Index ***********************************/
put_amf_string(pb, "videosize");
flv->videosize_offset = avio_tell(pb);
flv->videosize = 0;
put_amf_double(pb, 0); // delayed write
/************************************************************************/
put_amf_string(pb, "videocodecid");
put_amf_double(pb, video_enc->codec_tag);
put_amf_string(pb, "width");
put_amf_double(pb, video_enc->width);
put_amf_string(pb, "height");
put_amf_double(pb, video_enc->height);
put_amf_string(pb, "framerate");
put_amf_double(pb, framerate);
put_amf_string(pb, "videodatarate");
put_amf_double(pb, video_enc->bit_rate / 1024.0);
}
if(audio_enc)
{
/********** Add KeyFrame Index ***********************************/
put_amf_string(pb, "audiosize");
flv->audiosize_offset = avio_tell(pb);
flv->audiosize = 0;
put_amf_double(pb, 0); // delayed write
/************************************************************************/
put_amf_string(pb, "audiocodecid");
put_amf_double(pb, audio_enc->codec_tag);
put_amf_string(pb, "audiosamplesize");
put_amf_double(pb, audio_enc->codec_id == CODEC_ID_PCM_U8 ? 8 : 16);
put_amf_string(pb, "audiosamplerate");
put_amf_double(pb, audio_enc->sample_rate);
put_amf_string(pb, "stereo");
put_amf_bool(pb, audio_enc->channels == 2);
put_amf_string(pb, "audiodatarate");
put_amf_double(pb, audio_enc->bit_rate / 1024.0);
}
while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if( !strcmp(tag->key, "width")
||!strcmp(tag->key, "height")
||!strcmp(tag->key, "videodatarate")
||!strcmp(tag->key, "framerate")
||!strcmp(tag->key, "videocodecid")
||!strcmp(tag->key, "audiodatarate")
||!strcmp(tag->key, "audiosamplerate")
||!strcmp(tag->key, "audiosamplesize")
||!strcmp(tag->key, "stereo")
||!strcmp(tag->key, "audiocodecid")
||!strcmp(tag->key, "duration")
||!strcmp(tag->key, "onMetaData")
){
av_log(s, AV_LOG_DEBUG, "ignoring metadata for %s\n", tag->key);
continue;
}
put_amf_string(pb, tag->key);
avio_w8(pb, AMF_DATA_TYPE_STRING);
put_amf_string(pb, tag->value);
metadata_count++;
}
put_amf_string(pb, "filesize");
flv->filesize_offset = avio_tell(pb);
put_amf_double(pb, 0); // delayed write
/********** Add KeyFrame Index ***********************************/
flv->acurframeindex = 0;
flv->framerate = framerate;
put_amf_string(pb, "lasttimestamp");
flv->lasttimestamp_offset = avio_tell(pb);
flv->lasttimestamp = 0;
put_amf_double(pb, 0); // delayed write
put_amf_string(pb, "lastkeyframetimestamp");
flv->lastkeyframetimestamp_offset = avio_tell(pb);
flv->lastkeyframetimestamp = 0;
put_amf_double(pb, 0); // delayed write
put_amf_string(pb, "lastkeyframelocation");
flv->lastkeyframelocation_offset = avio_tell(pb);
flv->lastkeyframelocation = 0;
put_amf_double(pb, 0); // delayed write
put_amf_string(pb, "keyframes");
put_amf_byte(pb, AMF_DATA_TYPE_OBJECT);
put_amf_string(pb, "filepositions");
flv->filepositions_offset = avio_tell(pb);
put_amf_dword_array(pb, 0); // delayed write
flv->filepositions.RemoveAll();
for(int i = 0; i < MAX_FLV_KEY_FRAME; i++)
{
put_amf_double(pb, 0); // delayed write
}
put_amf_string(pb, "times");
flv->filetimes_offset = avio_tell(pb);
put_amf_dword_array(pb, 0); // delayed write
flv->filetimes.RemoveAll();
for(int i = 0; i < MAX_FLV_KEY_FRAME; i++)
{
put_amf_double(pb, 0); // delayed write
}
flv->filetimesend_Pos = avio_tell(pb);
/************************************************************************/
put_amf_string(pb, "");
avio_w8(pb, AMF_END_OF_OBJECT);
/* write total size of tag */
data_size= avio_tell(pb) - metadata_size_pos - 10;
avio_seek(pb, metadata_count_pos, SEEK_SET);
avio_wb32(pb, metadata_count);
avio_seek(pb, metadata_size_pos, SEEK_SET);
avio_wb24(pb, data_size);
avio_skip(pb, data_size + 10 - 3);
avio_wb32(pb, data_size + 11);
for (i = 0; i < s->nb_streams; i++) {
AVCodecContext *enc = s->streams[i]->codec;
if (enc->codec_id == CODEC_ID_AAC || enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) {
int64_t pos;
avio_w8(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ?
FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO);
avio_wb24(pb, 0); // size patched later
avio_wb24(pb, 0); // ts
avio_w8(pb, 0); // ts ext
avio_wb24(pb, 0); // streamid
pos = avio_tell(pb);
if (enc->codec_id == CODEC_ID_AAC) {
avio_w8(pb, get_audio_flags(enc));
avio_w8(pb, 0); // AAC sequence header
avio_write(pb, enc->extradata, enc->extradata_size);
} else {
avio_w8(pb, enc->codec_tag | FLV_FRAME_KEY); // flags
avio_w8(pb, 0); // AVC sequence header
avio_wb24(pb, 0); // composition time
ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size);
}
data_size = avio_tell(pb) - pos;
avio_seek(pb, -data_size - 10, SEEK_CUR);
avio_wb24(pb, data_size);
avio_skip(pb, data_size + 10 - 3);
avio_wb32(pb, data_size + 11); // previous tag size
}
}
/********** Add KeyFrame Index ***********************************/
flv->datastart_offset = avio_tell(pb);
/************************************************************************/
return 0;
}