1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * FLV muxer 3cabdff1aSopenharmony_ci * Copyright (c) 2003 The FFmpeg Project 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 23cabdff1aSopenharmony_ci#include "libavutil/dict.h" 24cabdff1aSopenharmony_ci#include "libavutil/intfloat.h" 25cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 26cabdff1aSopenharmony_ci#include "libavutil/mathematics.h" 27cabdff1aSopenharmony_ci#include "libavcodec/mpeg4audio.h" 28cabdff1aSopenharmony_ci#include "avio.h" 29cabdff1aSopenharmony_ci#include "avc.h" 30cabdff1aSopenharmony_ci#include "avformat.h" 31cabdff1aSopenharmony_ci#include "flv.h" 32cabdff1aSopenharmony_ci#include "internal.h" 33cabdff1aSopenharmony_ci#include "mux.h" 34cabdff1aSopenharmony_ci#include "libavutil/opt.h" 35cabdff1aSopenharmony_ci#include "libavcodec/put_bits.h" 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_cistatic const AVCodecTag flv_video_codec_ids[] = { 39cabdff1aSopenharmony_ci { AV_CODEC_ID_FLV1, FLV_CODECID_H263 }, 40cabdff1aSopenharmony_ci { AV_CODEC_ID_H263, FLV_CODECID_REALH263 }, 41cabdff1aSopenharmony_ci { AV_CODEC_ID_MPEG4, FLV_CODECID_MPEG4 }, 42cabdff1aSopenharmony_ci { AV_CODEC_ID_FLASHSV, FLV_CODECID_SCREEN }, 43cabdff1aSopenharmony_ci { AV_CODEC_ID_FLASHSV2, FLV_CODECID_SCREEN2 }, 44cabdff1aSopenharmony_ci { AV_CODEC_ID_VP6F, FLV_CODECID_VP6 }, 45cabdff1aSopenharmony_ci { AV_CODEC_ID_VP6, FLV_CODECID_VP6 }, 46cabdff1aSopenharmony_ci { AV_CODEC_ID_VP6A, FLV_CODECID_VP6A }, 47cabdff1aSopenharmony_ci { AV_CODEC_ID_H264, FLV_CODECID_H264 }, 48cabdff1aSopenharmony_ci { AV_CODEC_ID_NONE, 0 } 49cabdff1aSopenharmony_ci}; 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_cistatic const AVCodecTag flv_audio_codec_ids[] = { 52cabdff1aSopenharmony_ci { AV_CODEC_ID_MP3, FLV_CODECID_MP3 >> FLV_AUDIO_CODECID_OFFSET }, 53cabdff1aSopenharmony_ci { AV_CODEC_ID_PCM_U8, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET }, 54cabdff1aSopenharmony_ci { AV_CODEC_ID_PCM_S16BE, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET }, 55cabdff1aSopenharmony_ci { AV_CODEC_ID_PCM_S16LE, FLV_CODECID_PCM_LE >> FLV_AUDIO_CODECID_OFFSET }, 56cabdff1aSopenharmony_ci { AV_CODEC_ID_ADPCM_SWF, FLV_CODECID_ADPCM >> FLV_AUDIO_CODECID_OFFSET }, 57cabdff1aSopenharmony_ci { AV_CODEC_ID_AAC, FLV_CODECID_AAC >> FLV_AUDIO_CODECID_OFFSET }, 58cabdff1aSopenharmony_ci { AV_CODEC_ID_NELLYMOSER, FLV_CODECID_NELLYMOSER >> FLV_AUDIO_CODECID_OFFSET }, 59cabdff1aSopenharmony_ci { AV_CODEC_ID_PCM_MULAW, FLV_CODECID_PCM_MULAW >> FLV_AUDIO_CODECID_OFFSET }, 60cabdff1aSopenharmony_ci { AV_CODEC_ID_PCM_ALAW, FLV_CODECID_PCM_ALAW >> FLV_AUDIO_CODECID_OFFSET }, 61cabdff1aSopenharmony_ci { AV_CODEC_ID_SPEEX, FLV_CODECID_SPEEX >> FLV_AUDIO_CODECID_OFFSET }, 62cabdff1aSopenharmony_ci { AV_CODEC_ID_NONE, 0 } 63cabdff1aSopenharmony_ci}; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_citypedef enum { 66cabdff1aSopenharmony_ci FLV_AAC_SEQ_HEADER_DETECT = (1 << 0), 67cabdff1aSopenharmony_ci FLV_NO_SEQUENCE_END = (1 << 1), 68cabdff1aSopenharmony_ci FLV_ADD_KEYFRAME_INDEX = (1 << 2), 69cabdff1aSopenharmony_ci FLV_NO_METADATA = (1 << 3), 70cabdff1aSopenharmony_ci FLV_NO_DURATION_FILESIZE = (1 << 4), 71cabdff1aSopenharmony_ci} FLVFlags; 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_citypedef struct FLVFileposition { 74cabdff1aSopenharmony_ci int64_t keyframe_position; 75cabdff1aSopenharmony_ci double keyframe_timestamp; 76cabdff1aSopenharmony_ci struct FLVFileposition *next; 77cabdff1aSopenharmony_ci} FLVFileposition; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_citypedef struct FLVContext { 80cabdff1aSopenharmony_ci AVClass *av_class; 81cabdff1aSopenharmony_ci int reserved; 82cabdff1aSopenharmony_ci int64_t duration_offset; 83cabdff1aSopenharmony_ci int64_t filesize_offset; 84cabdff1aSopenharmony_ci int64_t duration; 85cabdff1aSopenharmony_ci int64_t delay; ///< first dts delay (needed for AVC & Speex) 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci int64_t datastart_offset; 88cabdff1aSopenharmony_ci int64_t datasize_offset; 89cabdff1aSopenharmony_ci int64_t datasize; 90cabdff1aSopenharmony_ci int64_t videosize_offset; 91cabdff1aSopenharmony_ci int64_t videosize; 92cabdff1aSopenharmony_ci int64_t audiosize_offset; 93cabdff1aSopenharmony_ci int64_t audiosize; 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci int64_t metadata_size_pos; 96cabdff1aSopenharmony_ci int64_t metadata_totalsize_pos; 97cabdff1aSopenharmony_ci int64_t metadata_totalsize; 98cabdff1aSopenharmony_ci int64_t keyframe_index_size; 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci int64_t lasttimestamp_offset; 101cabdff1aSopenharmony_ci double lasttimestamp; 102cabdff1aSopenharmony_ci int64_t lastkeyframetimestamp_offset; 103cabdff1aSopenharmony_ci double lastkeyframetimestamp; 104cabdff1aSopenharmony_ci int64_t lastkeyframelocation_offset; 105cabdff1aSopenharmony_ci int64_t lastkeyframelocation; 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_ci int acurframeindex; 108cabdff1aSopenharmony_ci int64_t keyframes_info_offset; 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci int64_t filepositions_count; 111cabdff1aSopenharmony_ci FLVFileposition *filepositions; 112cabdff1aSopenharmony_ci FLVFileposition *head_filepositions; 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci AVCodecParameters *audio_par; 115cabdff1aSopenharmony_ci AVCodecParameters *video_par; 116cabdff1aSopenharmony_ci double framerate; 117cabdff1aSopenharmony_ci AVCodecParameters *data_par; 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci int flags; 120cabdff1aSopenharmony_ci} FLVContext; 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_citypedef struct FLVStreamContext { 123cabdff1aSopenharmony_ci int64_t last_ts; ///< last timestamp for each stream 124cabdff1aSopenharmony_ci} FLVStreamContext; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_cistatic int get_audio_flags(AVFormatContext *s, AVCodecParameters *par) 127cabdff1aSopenharmony_ci{ 128cabdff1aSopenharmony_ci int flags = (par->bits_per_coded_sample == 16) ? FLV_SAMPLESSIZE_16BIT 129cabdff1aSopenharmony_ci : FLV_SAMPLESSIZE_8BIT; 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_AAC) // specs force these parameters 132cabdff1aSopenharmony_ci return FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ | 133cabdff1aSopenharmony_ci FLV_SAMPLESSIZE_16BIT | FLV_STEREO; 134cabdff1aSopenharmony_ci else if (par->codec_id == AV_CODEC_ID_SPEEX) { 135cabdff1aSopenharmony_ci if (par->sample_rate != 16000) { 136cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 137cabdff1aSopenharmony_ci "FLV only supports wideband (16kHz) Speex audio\n"); 138cabdff1aSopenharmony_ci return AVERROR(EINVAL); 139cabdff1aSopenharmony_ci } 140cabdff1aSopenharmony_ci if (par->ch_layout.nb_channels != 1) { 141cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "FLV only supports mono Speex audio\n"); 142cabdff1aSopenharmony_ci return AVERROR(EINVAL); 143cabdff1aSopenharmony_ci } 144cabdff1aSopenharmony_ci return FLV_CODECID_SPEEX | FLV_SAMPLERATE_11025HZ | FLV_SAMPLESSIZE_16BIT; 145cabdff1aSopenharmony_ci } else { 146cabdff1aSopenharmony_ci switch (par->sample_rate) { 147cabdff1aSopenharmony_ci case 48000: 148cabdff1aSopenharmony_ci // 48khz mp3 is stored with 44k1 samplerate identifer 149cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_MP3) { 150cabdff1aSopenharmony_ci flags |= FLV_SAMPLERATE_44100HZ; 151cabdff1aSopenharmony_ci break; 152cabdff1aSopenharmony_ci } else { 153cabdff1aSopenharmony_ci goto error; 154cabdff1aSopenharmony_ci } 155cabdff1aSopenharmony_ci case 44100: 156cabdff1aSopenharmony_ci flags |= FLV_SAMPLERATE_44100HZ; 157cabdff1aSopenharmony_ci break; 158cabdff1aSopenharmony_ci case 22050: 159cabdff1aSopenharmony_ci flags |= FLV_SAMPLERATE_22050HZ; 160cabdff1aSopenharmony_ci break; 161cabdff1aSopenharmony_ci case 11025: 162cabdff1aSopenharmony_ci flags |= FLV_SAMPLERATE_11025HZ; 163cabdff1aSopenharmony_ci break; 164cabdff1aSopenharmony_ci case 16000: // nellymoser only 165cabdff1aSopenharmony_ci case 8000: // nellymoser only 166cabdff1aSopenharmony_ci case 5512: // not MP3 167cabdff1aSopenharmony_ci if (par->codec_id != AV_CODEC_ID_MP3) { 168cabdff1aSopenharmony_ci flags |= FLV_SAMPLERATE_SPECIAL; 169cabdff1aSopenharmony_ci break; 170cabdff1aSopenharmony_ci } 171cabdff1aSopenharmony_ci default: 172cabdff1aSopenharmony_cierror: 173cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 174cabdff1aSopenharmony_ci "FLV does not support sample rate %d, " 175cabdff1aSopenharmony_ci "choose from (44100, 22050, 11025)\n", par->sample_rate); 176cabdff1aSopenharmony_ci return AVERROR(EINVAL); 177cabdff1aSopenharmony_ci } 178cabdff1aSopenharmony_ci } 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci if (par->ch_layout.nb_channels > 1) 181cabdff1aSopenharmony_ci flags |= FLV_STEREO; 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_ci switch (par->codec_id) { 184cabdff1aSopenharmony_ci case AV_CODEC_ID_MP3: 185cabdff1aSopenharmony_ci flags |= FLV_CODECID_MP3 | FLV_SAMPLESSIZE_16BIT; 186cabdff1aSopenharmony_ci break; 187cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_U8: 188cabdff1aSopenharmony_ci flags |= FLV_CODECID_PCM | FLV_SAMPLESSIZE_8BIT; 189cabdff1aSopenharmony_ci break; 190cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_S16BE: 191cabdff1aSopenharmony_ci flags |= FLV_CODECID_PCM | FLV_SAMPLESSIZE_16BIT; 192cabdff1aSopenharmony_ci break; 193cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_S16LE: 194cabdff1aSopenharmony_ci flags |= FLV_CODECID_PCM_LE | FLV_SAMPLESSIZE_16BIT; 195cabdff1aSopenharmony_ci break; 196cabdff1aSopenharmony_ci case AV_CODEC_ID_ADPCM_SWF: 197cabdff1aSopenharmony_ci flags |= FLV_CODECID_ADPCM | FLV_SAMPLESSIZE_16BIT; 198cabdff1aSopenharmony_ci break; 199cabdff1aSopenharmony_ci case AV_CODEC_ID_NELLYMOSER: 200cabdff1aSopenharmony_ci if (par->sample_rate == 8000) 201cabdff1aSopenharmony_ci flags |= FLV_CODECID_NELLYMOSER_8KHZ_MONO | FLV_SAMPLESSIZE_16BIT; 202cabdff1aSopenharmony_ci else if (par->sample_rate == 16000) 203cabdff1aSopenharmony_ci flags |= FLV_CODECID_NELLYMOSER_16KHZ_MONO | FLV_SAMPLESSIZE_16BIT; 204cabdff1aSopenharmony_ci else 205cabdff1aSopenharmony_ci flags |= FLV_CODECID_NELLYMOSER | FLV_SAMPLESSIZE_16BIT; 206cabdff1aSopenharmony_ci break; 207cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_MULAW: 208cabdff1aSopenharmony_ci flags = FLV_CODECID_PCM_MULAW | FLV_SAMPLERATE_SPECIAL | FLV_SAMPLESSIZE_16BIT; 209cabdff1aSopenharmony_ci break; 210cabdff1aSopenharmony_ci case AV_CODEC_ID_PCM_ALAW: 211cabdff1aSopenharmony_ci flags = FLV_CODECID_PCM_ALAW | FLV_SAMPLERATE_SPECIAL | FLV_SAMPLESSIZE_16BIT; 212cabdff1aSopenharmony_ci break; 213cabdff1aSopenharmony_ci case 0: 214cabdff1aSopenharmony_ci flags |= par->codec_tag << 4; 215cabdff1aSopenharmony_ci break; 216cabdff1aSopenharmony_ci default: 217cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Audio codec '%s' not compatible with FLV\n", 218cabdff1aSopenharmony_ci avcodec_get_name(par->codec_id)); 219cabdff1aSopenharmony_ci return AVERROR(EINVAL); 220cabdff1aSopenharmony_ci } 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_ci return flags; 223cabdff1aSopenharmony_ci} 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_cistatic void put_amf_string(AVIOContext *pb, const char *str) 226cabdff1aSopenharmony_ci{ 227cabdff1aSopenharmony_ci size_t len = strlen(str); 228cabdff1aSopenharmony_ci avio_wb16(pb, len); 229cabdff1aSopenharmony_ci avio_write(pb, str, len); 230cabdff1aSopenharmony_ci} 231cabdff1aSopenharmony_ci 232cabdff1aSopenharmony_ci// FLV timestamps are 32 bits signed, RTMP timestamps should be 32-bit unsigned 233cabdff1aSopenharmony_cistatic void put_timestamp(AVIOContext *pb, int64_t ts) { 234cabdff1aSopenharmony_ci avio_wb24(pb, ts & 0xFFFFFF); 235cabdff1aSopenharmony_ci avio_w8(pb, (ts >> 24) & 0x7F); 236cabdff1aSopenharmony_ci} 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_cistatic void put_avc_eos_tag(AVIOContext *pb, unsigned ts) 239cabdff1aSopenharmony_ci{ 240cabdff1aSopenharmony_ci avio_w8(pb, FLV_TAG_TYPE_VIDEO); 241cabdff1aSopenharmony_ci avio_wb24(pb, 5); /* Tag Data Size */ 242cabdff1aSopenharmony_ci put_timestamp(pb, ts); 243cabdff1aSopenharmony_ci avio_wb24(pb, 0); /* StreamId = 0 */ 244cabdff1aSopenharmony_ci avio_w8(pb, 23); /* ub[4] FrameType = 1, ub[4] CodecId = 7 */ 245cabdff1aSopenharmony_ci avio_w8(pb, 2); /* AVC end of sequence */ 246cabdff1aSopenharmony_ci avio_wb24(pb, 0); /* Always 0 for AVC EOS. */ 247cabdff1aSopenharmony_ci avio_wb32(pb, 16); /* Size of FLV tag */ 248cabdff1aSopenharmony_ci} 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_cistatic void put_amf_double(AVIOContext *pb, double d) 251cabdff1aSopenharmony_ci{ 252cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_NUMBER); 253cabdff1aSopenharmony_ci avio_wb64(pb, av_double2int(d)); 254cabdff1aSopenharmony_ci} 255cabdff1aSopenharmony_ci 256cabdff1aSopenharmony_cistatic void put_amf_byte(AVIOContext *pb, unsigned char abyte) 257cabdff1aSopenharmony_ci{ 258cabdff1aSopenharmony_ci avio_w8(pb, abyte); 259cabdff1aSopenharmony_ci} 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_cistatic void put_amf_dword_array(AVIOContext *pb, uint32_t dw) 262cabdff1aSopenharmony_ci{ 263cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_ARRAY); 264cabdff1aSopenharmony_ci avio_wb32(pb, dw); 265cabdff1aSopenharmony_ci} 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_cistatic void put_amf_bool(AVIOContext *pb, int b) 268cabdff1aSopenharmony_ci{ 269cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_BOOL); 270cabdff1aSopenharmony_ci avio_w8(pb, !!b); 271cabdff1aSopenharmony_ci} 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_cistatic void write_metadata(AVFormatContext *s, unsigned int ts) 274cabdff1aSopenharmony_ci{ 275cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 276cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 277cabdff1aSopenharmony_ci int write_duration_filesize = !(flv->flags & FLV_NO_DURATION_FILESIZE); 278cabdff1aSopenharmony_ci int metadata_count = 0; 279cabdff1aSopenharmony_ci int64_t metadata_count_pos; 280cabdff1aSopenharmony_ci AVDictionaryEntry *tag = NULL; 281cabdff1aSopenharmony_ci 282cabdff1aSopenharmony_ci /* write meta_tag */ 283cabdff1aSopenharmony_ci avio_w8(pb, FLV_TAG_TYPE_META); // tag type META 284cabdff1aSopenharmony_ci flv->metadata_size_pos = avio_tell(pb); 285cabdff1aSopenharmony_ci avio_wb24(pb, 0); // size of data part (sum of all parts below) 286cabdff1aSopenharmony_ci put_timestamp(pb, ts); // timestamp 287cabdff1aSopenharmony_ci avio_wb24(pb, 0); // reserved 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci /* now data of data_size size */ 290cabdff1aSopenharmony_ci 291cabdff1aSopenharmony_ci /* first event name as a string */ 292cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_STRING); 293cabdff1aSopenharmony_ci put_amf_string(pb, "onMetaData"); // 12 bytes 294cabdff1aSopenharmony_ci 295cabdff1aSopenharmony_ci /* mixed array (hash) with size and string/type/data tuples */ 296cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); 297cabdff1aSopenharmony_ci metadata_count_pos = avio_tell(pb); 298cabdff1aSopenharmony_ci metadata_count = 4 * !!flv->video_par + 299cabdff1aSopenharmony_ci 5 * !!flv->audio_par + 300cabdff1aSopenharmony_ci 1 * !!flv->data_par; 301cabdff1aSopenharmony_ci if (write_duration_filesize) { 302cabdff1aSopenharmony_ci metadata_count += 2; // +2 for duration and file size 303cabdff1aSopenharmony_ci } 304cabdff1aSopenharmony_ci avio_wb32(pb, metadata_count); 305cabdff1aSopenharmony_ci 306cabdff1aSopenharmony_ci if (write_duration_filesize) { 307cabdff1aSopenharmony_ci put_amf_string(pb, "duration"); 308cabdff1aSopenharmony_ci flv->duration_offset = avio_tell(pb); 309cabdff1aSopenharmony_ci // fill in the guessed duration, it'll be corrected later if incorrect 310cabdff1aSopenharmony_ci put_amf_double(pb, s->duration / AV_TIME_BASE); 311cabdff1aSopenharmony_ci } 312cabdff1aSopenharmony_ci 313cabdff1aSopenharmony_ci if (flv->video_par) { 314cabdff1aSopenharmony_ci put_amf_string(pb, "width"); 315cabdff1aSopenharmony_ci put_amf_double(pb, flv->video_par->width); 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci put_amf_string(pb, "height"); 318cabdff1aSopenharmony_ci put_amf_double(pb, flv->video_par->height); 319cabdff1aSopenharmony_ci 320cabdff1aSopenharmony_ci put_amf_string(pb, "videodatarate"); 321cabdff1aSopenharmony_ci put_amf_double(pb, flv->video_par->bit_rate / 1024.0); 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci if (flv->framerate != 0.0) { 324cabdff1aSopenharmony_ci put_amf_string(pb, "framerate"); 325cabdff1aSopenharmony_ci put_amf_double(pb, flv->framerate); 326cabdff1aSopenharmony_ci metadata_count++; 327cabdff1aSopenharmony_ci } 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci put_amf_string(pb, "videocodecid"); 330cabdff1aSopenharmony_ci put_amf_double(pb, flv->video_par->codec_tag); 331cabdff1aSopenharmony_ci } 332cabdff1aSopenharmony_ci 333cabdff1aSopenharmony_ci if (flv->audio_par) { 334cabdff1aSopenharmony_ci put_amf_string(pb, "audiodatarate"); 335cabdff1aSopenharmony_ci put_amf_double(pb, flv->audio_par->bit_rate / 1024.0); 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci put_amf_string(pb, "audiosamplerate"); 338cabdff1aSopenharmony_ci put_amf_double(pb, flv->audio_par->sample_rate); 339cabdff1aSopenharmony_ci 340cabdff1aSopenharmony_ci put_amf_string(pb, "audiosamplesize"); 341cabdff1aSopenharmony_ci put_amf_double(pb, flv->audio_par->codec_id == AV_CODEC_ID_PCM_U8 ? 8 : 16); 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_ci put_amf_string(pb, "stereo"); 344cabdff1aSopenharmony_ci put_amf_bool(pb, flv->audio_par->ch_layout.nb_channels == 2); 345cabdff1aSopenharmony_ci 346cabdff1aSopenharmony_ci put_amf_string(pb, "audiocodecid"); 347cabdff1aSopenharmony_ci put_amf_double(pb, flv->audio_par->codec_tag); 348cabdff1aSopenharmony_ci } 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci if (flv->data_par) { 351cabdff1aSopenharmony_ci put_amf_string(pb, "datastream"); 352cabdff1aSopenharmony_ci put_amf_double(pb, 0.0); 353cabdff1aSopenharmony_ci } 354cabdff1aSopenharmony_ci 355cabdff1aSopenharmony_ci ff_standardize_creation_time(s); 356cabdff1aSopenharmony_ci while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { 357cabdff1aSopenharmony_ci if( !strcmp(tag->key, "width") 358cabdff1aSopenharmony_ci ||!strcmp(tag->key, "height") 359cabdff1aSopenharmony_ci ||!strcmp(tag->key, "videodatarate") 360cabdff1aSopenharmony_ci ||!strcmp(tag->key, "framerate") 361cabdff1aSopenharmony_ci ||!strcmp(tag->key, "videocodecid") 362cabdff1aSopenharmony_ci ||!strcmp(tag->key, "audiodatarate") 363cabdff1aSopenharmony_ci ||!strcmp(tag->key, "audiosamplerate") 364cabdff1aSopenharmony_ci ||!strcmp(tag->key, "audiosamplesize") 365cabdff1aSopenharmony_ci ||!strcmp(tag->key, "stereo") 366cabdff1aSopenharmony_ci ||!strcmp(tag->key, "audiocodecid") 367cabdff1aSopenharmony_ci ||!strcmp(tag->key, "duration") 368cabdff1aSopenharmony_ci ||!strcmp(tag->key, "onMetaData") 369cabdff1aSopenharmony_ci ||!strcmp(tag->key, "datasize") 370cabdff1aSopenharmony_ci ||!strcmp(tag->key, "lasttimestamp") 371cabdff1aSopenharmony_ci ||!strcmp(tag->key, "totalframes") 372cabdff1aSopenharmony_ci ||!strcmp(tag->key, "hasAudio") 373cabdff1aSopenharmony_ci ||!strcmp(tag->key, "hasVideo") 374cabdff1aSopenharmony_ci ||!strcmp(tag->key, "hasCuePoints") 375cabdff1aSopenharmony_ci ||!strcmp(tag->key, "hasMetadata") 376cabdff1aSopenharmony_ci ||!strcmp(tag->key, "hasKeyframes") 377cabdff1aSopenharmony_ci ){ 378cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Ignoring metadata for %s\n", tag->key); 379cabdff1aSopenharmony_ci continue; 380cabdff1aSopenharmony_ci } 381cabdff1aSopenharmony_ci put_amf_string(pb, tag->key); 382cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_STRING); 383cabdff1aSopenharmony_ci put_amf_string(pb, tag->value); 384cabdff1aSopenharmony_ci metadata_count++; 385cabdff1aSopenharmony_ci } 386cabdff1aSopenharmony_ci 387cabdff1aSopenharmony_ci if (write_duration_filesize) { 388cabdff1aSopenharmony_ci put_amf_string(pb, "filesize"); 389cabdff1aSopenharmony_ci flv->filesize_offset = avio_tell(pb); 390cabdff1aSopenharmony_ci put_amf_double(pb, 0); // delayed write 391cabdff1aSopenharmony_ci } 392cabdff1aSopenharmony_ci 393cabdff1aSopenharmony_ci if (flv->flags & FLV_ADD_KEYFRAME_INDEX) { 394cabdff1aSopenharmony_ci flv->acurframeindex = 0; 395cabdff1aSopenharmony_ci flv->keyframe_index_size = 0; 396cabdff1aSopenharmony_ci 397cabdff1aSopenharmony_ci put_amf_string(pb, "hasVideo"); 398cabdff1aSopenharmony_ci put_amf_bool(pb, !!flv->video_par); 399cabdff1aSopenharmony_ci metadata_count++; 400cabdff1aSopenharmony_ci 401cabdff1aSopenharmony_ci put_amf_string(pb, "hasKeyframes"); 402cabdff1aSopenharmony_ci put_amf_bool(pb, 1); 403cabdff1aSopenharmony_ci metadata_count++; 404cabdff1aSopenharmony_ci 405cabdff1aSopenharmony_ci put_amf_string(pb, "hasAudio"); 406cabdff1aSopenharmony_ci put_amf_bool(pb, !!flv->audio_par); 407cabdff1aSopenharmony_ci metadata_count++; 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci put_amf_string(pb, "hasMetadata"); 410cabdff1aSopenharmony_ci put_amf_bool(pb, 1); 411cabdff1aSopenharmony_ci metadata_count++; 412cabdff1aSopenharmony_ci 413cabdff1aSopenharmony_ci put_amf_string(pb, "canSeekToEnd"); 414cabdff1aSopenharmony_ci put_amf_bool(pb, 1); 415cabdff1aSopenharmony_ci metadata_count++; 416cabdff1aSopenharmony_ci 417cabdff1aSopenharmony_ci put_amf_string(pb, "datasize"); 418cabdff1aSopenharmony_ci flv->datasize_offset = avio_tell(pb); 419cabdff1aSopenharmony_ci flv->datasize = 0; 420cabdff1aSopenharmony_ci put_amf_double(pb, flv->datasize); 421cabdff1aSopenharmony_ci metadata_count++; 422cabdff1aSopenharmony_ci 423cabdff1aSopenharmony_ci put_amf_string(pb, "videosize"); 424cabdff1aSopenharmony_ci flv->videosize_offset = avio_tell(pb); 425cabdff1aSopenharmony_ci flv->videosize = 0; 426cabdff1aSopenharmony_ci put_amf_double(pb, flv->videosize); 427cabdff1aSopenharmony_ci metadata_count++; 428cabdff1aSopenharmony_ci 429cabdff1aSopenharmony_ci put_amf_string(pb, "audiosize"); 430cabdff1aSopenharmony_ci flv->audiosize_offset = avio_tell(pb); 431cabdff1aSopenharmony_ci flv->audiosize = 0; 432cabdff1aSopenharmony_ci put_amf_double(pb, flv->audiosize); 433cabdff1aSopenharmony_ci metadata_count++; 434cabdff1aSopenharmony_ci 435cabdff1aSopenharmony_ci put_amf_string(pb, "lasttimestamp"); 436cabdff1aSopenharmony_ci flv->lasttimestamp_offset = avio_tell(pb); 437cabdff1aSopenharmony_ci flv->lasttimestamp = 0; 438cabdff1aSopenharmony_ci put_amf_double(pb, 0); 439cabdff1aSopenharmony_ci metadata_count++; 440cabdff1aSopenharmony_ci 441cabdff1aSopenharmony_ci put_amf_string(pb, "lastkeyframetimestamp"); 442cabdff1aSopenharmony_ci flv->lastkeyframetimestamp_offset = avio_tell(pb); 443cabdff1aSopenharmony_ci flv->lastkeyframetimestamp = 0; 444cabdff1aSopenharmony_ci put_amf_double(pb, 0); 445cabdff1aSopenharmony_ci metadata_count++; 446cabdff1aSopenharmony_ci 447cabdff1aSopenharmony_ci put_amf_string(pb, "lastkeyframelocation"); 448cabdff1aSopenharmony_ci flv->lastkeyframelocation_offset = avio_tell(pb); 449cabdff1aSopenharmony_ci flv->lastkeyframelocation = 0; 450cabdff1aSopenharmony_ci put_amf_double(pb, 0); 451cabdff1aSopenharmony_ci metadata_count++; 452cabdff1aSopenharmony_ci 453cabdff1aSopenharmony_ci put_amf_string(pb, "keyframes"); 454cabdff1aSopenharmony_ci put_amf_byte(pb, AMF_DATA_TYPE_OBJECT); 455cabdff1aSopenharmony_ci metadata_count++; 456cabdff1aSopenharmony_ci 457cabdff1aSopenharmony_ci flv->keyframes_info_offset = avio_tell(pb); 458cabdff1aSopenharmony_ci } 459cabdff1aSopenharmony_ci 460cabdff1aSopenharmony_ci put_amf_string(pb, ""); 461cabdff1aSopenharmony_ci avio_w8(pb, AMF_END_OF_OBJECT); 462cabdff1aSopenharmony_ci 463cabdff1aSopenharmony_ci /* write total size of tag */ 464cabdff1aSopenharmony_ci flv->metadata_totalsize = avio_tell(pb) - flv->metadata_size_pos - 10; 465cabdff1aSopenharmony_ci 466cabdff1aSopenharmony_ci avio_seek(pb, metadata_count_pos, SEEK_SET); 467cabdff1aSopenharmony_ci avio_wb32(pb, metadata_count); 468cabdff1aSopenharmony_ci 469cabdff1aSopenharmony_ci avio_seek(pb, flv->metadata_size_pos, SEEK_SET); 470cabdff1aSopenharmony_ci avio_wb24(pb, flv->metadata_totalsize); 471cabdff1aSopenharmony_ci avio_skip(pb, flv->metadata_totalsize + 10 - 3); 472cabdff1aSopenharmony_ci flv->metadata_totalsize_pos = avio_tell(pb); 473cabdff1aSopenharmony_ci avio_wb32(pb, flv->metadata_totalsize + 11); 474cabdff1aSopenharmony_ci} 475cabdff1aSopenharmony_ci 476cabdff1aSopenharmony_cistatic int unsupported_codec(AVFormatContext *s, 477cabdff1aSopenharmony_ci const char* type, int codec_id) 478cabdff1aSopenharmony_ci{ 479cabdff1aSopenharmony_ci const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id); 480cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 481cabdff1aSopenharmony_ci "%s codec %s not compatible with flv\n", 482cabdff1aSopenharmony_ci type, 483cabdff1aSopenharmony_ci desc ? desc->name : "unknown"); 484cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 485cabdff1aSopenharmony_ci} 486cabdff1aSopenharmony_ci 487cabdff1aSopenharmony_cistatic void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, int64_t ts) { 488cabdff1aSopenharmony_ci int64_t data_size; 489cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 490cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 491cabdff1aSopenharmony_ci 492cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264 493cabdff1aSopenharmony_ci || par->codec_id == AV_CODEC_ID_MPEG4) { 494cabdff1aSopenharmony_ci int64_t pos; 495cabdff1aSopenharmony_ci avio_w8(pb, 496cabdff1aSopenharmony_ci par->codec_type == AVMEDIA_TYPE_VIDEO ? 497cabdff1aSopenharmony_ci FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); 498cabdff1aSopenharmony_ci avio_wb24(pb, 0); // size patched later 499cabdff1aSopenharmony_ci put_timestamp(pb, ts); 500cabdff1aSopenharmony_ci avio_wb24(pb, 0); // streamid 501cabdff1aSopenharmony_ci pos = avio_tell(pb); 502cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_AAC) { 503cabdff1aSopenharmony_ci avio_w8(pb, get_audio_flags(s, par)); 504cabdff1aSopenharmony_ci avio_w8(pb, 0); // AAC sequence header 505cabdff1aSopenharmony_ci 506cabdff1aSopenharmony_ci if (!par->extradata_size && (flv->flags & FLV_AAC_SEQ_HEADER_DETECT)) { 507cabdff1aSopenharmony_ci PutBitContext pbc; 508cabdff1aSopenharmony_ci int samplerate_index; 509cabdff1aSopenharmony_ci int channels = flv->audio_par->ch_layout.nb_channels 510cabdff1aSopenharmony_ci - (flv->audio_par->ch_layout.nb_channels == 8 ? 1 : 0); 511cabdff1aSopenharmony_ci uint8_t data[2]; 512cabdff1aSopenharmony_ci 513cabdff1aSopenharmony_ci for (samplerate_index = 0; samplerate_index < 16; 514cabdff1aSopenharmony_ci samplerate_index++) 515cabdff1aSopenharmony_ci if (flv->audio_par->sample_rate 516cabdff1aSopenharmony_ci == ff_mpeg4audio_sample_rates[samplerate_index]) 517cabdff1aSopenharmony_ci break; 518cabdff1aSopenharmony_ci 519cabdff1aSopenharmony_ci init_put_bits(&pbc, data, sizeof(data)); 520cabdff1aSopenharmony_ci put_bits(&pbc, 5, flv->audio_par->profile + 1); //profile 521cabdff1aSopenharmony_ci put_bits(&pbc, 4, samplerate_index); //sample rate index 522cabdff1aSopenharmony_ci put_bits(&pbc, 4, channels); 523cabdff1aSopenharmony_ci put_bits(&pbc, 1, 0); //frame length - 1024 samples 524cabdff1aSopenharmony_ci put_bits(&pbc, 1, 0); //does not depend on core coder 525cabdff1aSopenharmony_ci put_bits(&pbc, 1, 0); //is not extension 526cabdff1aSopenharmony_ci flush_put_bits(&pbc); 527cabdff1aSopenharmony_ci 528cabdff1aSopenharmony_ci avio_w8(pb, data[0]); 529cabdff1aSopenharmony_ci avio_w8(pb, data[1]); 530cabdff1aSopenharmony_ci 531cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "AAC sequence header: %02x %02x.\n", 532cabdff1aSopenharmony_ci data[0], data[1]); 533cabdff1aSopenharmony_ci } 534cabdff1aSopenharmony_ci avio_write(pb, par->extradata, par->extradata_size); 535cabdff1aSopenharmony_ci } else { 536cabdff1aSopenharmony_ci avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags 537cabdff1aSopenharmony_ci avio_w8(pb, 0); // AVC sequence header 538cabdff1aSopenharmony_ci avio_wb24(pb, 0); // composition time 539cabdff1aSopenharmony_ci ff_isom_write_avcc(pb, par->extradata, par->extradata_size); 540cabdff1aSopenharmony_ci } 541cabdff1aSopenharmony_ci data_size = avio_tell(pb) - pos; 542cabdff1aSopenharmony_ci avio_seek(pb, -data_size - 10, SEEK_CUR); 543cabdff1aSopenharmony_ci avio_wb24(pb, data_size); 544cabdff1aSopenharmony_ci avio_skip(pb, data_size + 10 - 3); 545cabdff1aSopenharmony_ci avio_wb32(pb, data_size + 11); // previous tag size 546cabdff1aSopenharmony_ci } 547cabdff1aSopenharmony_ci} 548cabdff1aSopenharmony_ci 549cabdff1aSopenharmony_cistatic int flv_append_keyframe_info(AVFormatContext *s, FLVContext *flv, double ts, int64_t pos) 550cabdff1aSopenharmony_ci{ 551cabdff1aSopenharmony_ci FLVFileposition *position = av_malloc(sizeof(FLVFileposition)); 552cabdff1aSopenharmony_ci 553cabdff1aSopenharmony_ci if (!position) { 554cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "no mem for add keyframe index!\n"); 555cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 556cabdff1aSopenharmony_ci } 557cabdff1aSopenharmony_ci 558cabdff1aSopenharmony_ci position->keyframe_timestamp = ts; 559cabdff1aSopenharmony_ci position->keyframe_position = pos; 560cabdff1aSopenharmony_ci 561cabdff1aSopenharmony_ci if (!flv->filepositions_count) { 562cabdff1aSopenharmony_ci flv->filepositions = position; 563cabdff1aSopenharmony_ci flv->head_filepositions = flv->filepositions; 564cabdff1aSopenharmony_ci position->next = NULL; 565cabdff1aSopenharmony_ci } else { 566cabdff1aSopenharmony_ci flv->filepositions->next = position; 567cabdff1aSopenharmony_ci position->next = NULL; 568cabdff1aSopenharmony_ci flv->filepositions = flv->filepositions->next; 569cabdff1aSopenharmony_ci } 570cabdff1aSopenharmony_ci 571cabdff1aSopenharmony_ci flv->filepositions_count++; 572cabdff1aSopenharmony_ci 573cabdff1aSopenharmony_ci return 0; 574cabdff1aSopenharmony_ci} 575cabdff1aSopenharmony_ci 576cabdff1aSopenharmony_cistatic int shift_data(AVFormatContext *s) 577cabdff1aSopenharmony_ci{ 578cabdff1aSopenharmony_ci int ret; 579cabdff1aSopenharmony_ci int64_t metadata_size = 0; 580cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 581cabdff1aSopenharmony_ci 582cabdff1aSopenharmony_ci metadata_size = flv->filepositions_count * 9 * 2 + 10; /* filepositions and times value */ 583cabdff1aSopenharmony_ci metadata_size += 2 + 13; /* filepositions String */ 584cabdff1aSopenharmony_ci metadata_size += 2 + 5; /* times String */ 585cabdff1aSopenharmony_ci metadata_size += 3; /* Object end */ 586cabdff1aSopenharmony_ci 587cabdff1aSopenharmony_ci flv->keyframe_index_size = metadata_size; 588cabdff1aSopenharmony_ci 589cabdff1aSopenharmony_ci if (metadata_size < 0) 590cabdff1aSopenharmony_ci return metadata_size; 591cabdff1aSopenharmony_ci 592cabdff1aSopenharmony_ci ret = ff_format_shift_data(s, flv->keyframes_info_offset, metadata_size); 593cabdff1aSopenharmony_ci if (ret < 0) 594cabdff1aSopenharmony_ci return ret; 595cabdff1aSopenharmony_ci 596cabdff1aSopenharmony_ci avio_seek(s->pb, flv->metadata_size_pos, SEEK_SET); 597cabdff1aSopenharmony_ci avio_wb24(s->pb, flv->metadata_totalsize + metadata_size); 598cabdff1aSopenharmony_ci 599cabdff1aSopenharmony_ci avio_seek(s->pb, flv->metadata_totalsize_pos + metadata_size, SEEK_SET); 600cabdff1aSopenharmony_ci avio_wb32(s->pb, flv->metadata_totalsize + 11 + metadata_size); 601cabdff1aSopenharmony_ci 602cabdff1aSopenharmony_ci return 0; 603cabdff1aSopenharmony_ci} 604cabdff1aSopenharmony_ci 605cabdff1aSopenharmony_cistatic int flv_init(struct AVFormatContext *s) 606cabdff1aSopenharmony_ci{ 607cabdff1aSopenharmony_ci int i; 608cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 609cabdff1aSopenharmony_ci 610cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 611cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[i]->codecpar; 612cabdff1aSopenharmony_ci FLVStreamContext *sc; 613cabdff1aSopenharmony_ci switch (par->codec_type) { 614cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 615cabdff1aSopenharmony_ci if (s->streams[i]->avg_frame_rate.den && 616cabdff1aSopenharmony_ci s->streams[i]->avg_frame_rate.num) { 617cabdff1aSopenharmony_ci flv->framerate = av_q2d(s->streams[i]->avg_frame_rate); 618cabdff1aSopenharmony_ci } 619cabdff1aSopenharmony_ci if (flv->video_par) { 620cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 621cabdff1aSopenharmony_ci "at most one video stream is supported in flv\n"); 622cabdff1aSopenharmony_ci return AVERROR(EINVAL); 623cabdff1aSopenharmony_ci } 624cabdff1aSopenharmony_ci flv->video_par = par; 625cabdff1aSopenharmony_ci if (!ff_codec_get_tag(flv_video_codec_ids, par->codec_id)) 626cabdff1aSopenharmony_ci return unsupported_codec(s, "Video", par->codec_id); 627cabdff1aSopenharmony_ci 628cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_MPEG4 || 629cabdff1aSopenharmony_ci par->codec_id == AV_CODEC_ID_H263) { 630cabdff1aSopenharmony_ci int error = s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL; 631cabdff1aSopenharmony_ci av_log(s, error ? AV_LOG_ERROR : AV_LOG_WARNING, 632cabdff1aSopenharmony_ci "Codec %s is not supported in the official FLV specification,\n", avcodec_get_name(par->codec_id)); 633cabdff1aSopenharmony_ci 634cabdff1aSopenharmony_ci if (error) { 635cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 636cabdff1aSopenharmony_ci "use vstrict=-1 / -strict -1 to use it anyway.\n"); 637cabdff1aSopenharmony_ci return AVERROR(EINVAL); 638cabdff1aSopenharmony_ci } 639cabdff1aSopenharmony_ci } else if (par->codec_id == AV_CODEC_ID_VP6) { 640cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, 641cabdff1aSopenharmony_ci "Muxing VP6 in flv will produce flipped video on playback.\n"); 642cabdff1aSopenharmony_ci } 643cabdff1aSopenharmony_ci break; 644cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 645cabdff1aSopenharmony_ci if (flv->audio_par) { 646cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 647cabdff1aSopenharmony_ci "at most one audio stream is supported in flv\n"); 648cabdff1aSopenharmony_ci return AVERROR(EINVAL); 649cabdff1aSopenharmony_ci } 650cabdff1aSopenharmony_ci flv->audio_par = par; 651cabdff1aSopenharmony_ci if (get_audio_flags(s, par) < 0) 652cabdff1aSopenharmony_ci return unsupported_codec(s, "Audio", par->codec_id); 653cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_PCM_S16BE) 654cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, 655cabdff1aSopenharmony_ci "16-bit big-endian audio in flv is valid but most likely unplayable (hardware dependent); use s16le\n"); 656cabdff1aSopenharmony_ci break; 657cabdff1aSopenharmony_ci case AVMEDIA_TYPE_DATA: 658cabdff1aSopenharmony_ci if (par->codec_id != AV_CODEC_ID_TEXT && par->codec_id != AV_CODEC_ID_NONE) 659cabdff1aSopenharmony_ci return unsupported_codec(s, "Data", par->codec_id); 660cabdff1aSopenharmony_ci flv->data_par = par; 661cabdff1aSopenharmony_ci break; 662cabdff1aSopenharmony_ci case AVMEDIA_TYPE_SUBTITLE: 663cabdff1aSopenharmony_ci if (par->codec_id != AV_CODEC_ID_TEXT) { 664cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Subtitle codec '%s' for stream %d is not compatible with FLV\n", 665cabdff1aSopenharmony_ci avcodec_get_name(par->codec_id), i); 666cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 667cabdff1aSopenharmony_ci } 668cabdff1aSopenharmony_ci flv->data_par = par; 669cabdff1aSopenharmony_ci break; 670cabdff1aSopenharmony_ci default: 671cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Codec type '%s' for stream %d is not compatible with FLV\n", 672cabdff1aSopenharmony_ci av_get_media_type_string(par->codec_type), i); 673cabdff1aSopenharmony_ci return AVERROR(EINVAL); 674cabdff1aSopenharmony_ci } 675cabdff1aSopenharmony_ci avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */ 676cabdff1aSopenharmony_ci 677cabdff1aSopenharmony_ci sc = av_mallocz(sizeof(FLVStreamContext)); 678cabdff1aSopenharmony_ci if (!sc) 679cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 680cabdff1aSopenharmony_ci s->streams[i]->priv_data = sc; 681cabdff1aSopenharmony_ci sc->last_ts = -1; 682cabdff1aSopenharmony_ci } 683cabdff1aSopenharmony_ci 684cabdff1aSopenharmony_ci flv->delay = AV_NOPTS_VALUE; 685cabdff1aSopenharmony_ci 686cabdff1aSopenharmony_ci return 0; 687cabdff1aSopenharmony_ci} 688cabdff1aSopenharmony_ci 689cabdff1aSopenharmony_cistatic int flv_write_header(AVFormatContext *s) 690cabdff1aSopenharmony_ci{ 691cabdff1aSopenharmony_ci int i; 692cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 693cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 694cabdff1aSopenharmony_ci 695cabdff1aSopenharmony_ci avio_write(pb, "FLV", 3); 696cabdff1aSopenharmony_ci avio_w8(pb, 1); 697cabdff1aSopenharmony_ci avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!flv->audio_par + 698cabdff1aSopenharmony_ci FLV_HEADER_FLAG_HASVIDEO * !!flv->video_par); 699cabdff1aSopenharmony_ci avio_wb32(pb, 9); 700cabdff1aSopenharmony_ci avio_wb32(pb, 0); 701cabdff1aSopenharmony_ci 702cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) 703cabdff1aSopenharmony_ci if (s->streams[i]->codecpar->codec_tag == 5) { 704cabdff1aSopenharmony_ci avio_w8(pb, 8); // message type 705cabdff1aSopenharmony_ci avio_wb24(pb, 0); // include flags 706cabdff1aSopenharmony_ci avio_wb24(pb, 0); // time stamp 707cabdff1aSopenharmony_ci avio_wb32(pb, 0); // reserved 708cabdff1aSopenharmony_ci avio_wb32(pb, 11); // size 709cabdff1aSopenharmony_ci flv->reserved = 5; 710cabdff1aSopenharmony_ci } 711cabdff1aSopenharmony_ci 712cabdff1aSopenharmony_ci if (flv->flags & FLV_NO_METADATA) { 713cabdff1aSopenharmony_ci pb->seekable = 0; 714cabdff1aSopenharmony_ci } else { 715cabdff1aSopenharmony_ci write_metadata(s, 0); 716cabdff1aSopenharmony_ci } 717cabdff1aSopenharmony_ci 718cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 719cabdff1aSopenharmony_ci flv_write_codec_header(s, s->streams[i]->codecpar, 0); 720cabdff1aSopenharmony_ci } 721cabdff1aSopenharmony_ci 722cabdff1aSopenharmony_ci flv->datastart_offset = avio_tell(pb); 723cabdff1aSopenharmony_ci return 0; 724cabdff1aSopenharmony_ci} 725cabdff1aSopenharmony_ci 726cabdff1aSopenharmony_cistatic int flv_write_trailer(AVFormatContext *s) 727cabdff1aSopenharmony_ci{ 728cabdff1aSopenharmony_ci int64_t file_size; 729cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 730cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 731cabdff1aSopenharmony_ci int build_keyframes_idx = flv->flags & FLV_ADD_KEYFRAME_INDEX; 732cabdff1aSopenharmony_ci int i, res; 733cabdff1aSopenharmony_ci int64_t cur_pos = avio_tell(s->pb); 734cabdff1aSopenharmony_ci 735cabdff1aSopenharmony_ci if (build_keyframes_idx) { 736cabdff1aSopenharmony_ci const FLVFileposition *newflv_posinfo; 737cabdff1aSopenharmony_ci 738cabdff1aSopenharmony_ci avio_seek(pb, flv->videosize_offset, SEEK_SET); 739cabdff1aSopenharmony_ci put_amf_double(pb, flv->videosize); 740cabdff1aSopenharmony_ci 741cabdff1aSopenharmony_ci avio_seek(pb, flv->audiosize_offset, SEEK_SET); 742cabdff1aSopenharmony_ci put_amf_double(pb, flv->audiosize); 743cabdff1aSopenharmony_ci 744cabdff1aSopenharmony_ci avio_seek(pb, flv->lasttimestamp_offset, SEEK_SET); 745cabdff1aSopenharmony_ci put_amf_double(pb, flv->lasttimestamp); 746cabdff1aSopenharmony_ci 747cabdff1aSopenharmony_ci avio_seek(pb, flv->lastkeyframetimestamp_offset, SEEK_SET); 748cabdff1aSopenharmony_ci put_amf_double(pb, flv->lastkeyframetimestamp); 749cabdff1aSopenharmony_ci 750cabdff1aSopenharmony_ci avio_seek(pb, flv->lastkeyframelocation_offset, SEEK_SET); 751cabdff1aSopenharmony_ci put_amf_double(pb, flv->lastkeyframelocation + flv->keyframe_index_size); 752cabdff1aSopenharmony_ci avio_seek(pb, cur_pos, SEEK_SET); 753cabdff1aSopenharmony_ci 754cabdff1aSopenharmony_ci res = shift_data(s); 755cabdff1aSopenharmony_ci if (res < 0) { 756cabdff1aSopenharmony_ci goto end; 757cabdff1aSopenharmony_ci } 758cabdff1aSopenharmony_ci avio_seek(pb, flv->keyframes_info_offset, SEEK_SET); 759cabdff1aSopenharmony_ci put_amf_string(pb, "filepositions"); 760cabdff1aSopenharmony_ci put_amf_dword_array(pb, flv->filepositions_count); 761cabdff1aSopenharmony_ci for (newflv_posinfo = flv->head_filepositions; newflv_posinfo; newflv_posinfo = newflv_posinfo->next) { 762cabdff1aSopenharmony_ci put_amf_double(pb, newflv_posinfo->keyframe_position + flv->keyframe_index_size); 763cabdff1aSopenharmony_ci } 764cabdff1aSopenharmony_ci 765cabdff1aSopenharmony_ci put_amf_string(pb, "times"); 766cabdff1aSopenharmony_ci put_amf_dword_array(pb, flv->filepositions_count); 767cabdff1aSopenharmony_ci for (newflv_posinfo = flv->head_filepositions; newflv_posinfo; newflv_posinfo = newflv_posinfo->next) { 768cabdff1aSopenharmony_ci put_amf_double(pb, newflv_posinfo->keyframe_timestamp); 769cabdff1aSopenharmony_ci } 770cabdff1aSopenharmony_ci 771cabdff1aSopenharmony_ci put_amf_string(pb, ""); 772cabdff1aSopenharmony_ci avio_w8(pb, AMF_END_OF_OBJECT); 773cabdff1aSopenharmony_ci 774cabdff1aSopenharmony_ci avio_seek(pb, cur_pos + flv->keyframe_index_size, SEEK_SET); 775cabdff1aSopenharmony_ci } 776cabdff1aSopenharmony_ci 777cabdff1aSopenharmony_ciend: 778cabdff1aSopenharmony_ci if (flv->flags & FLV_NO_SEQUENCE_END) { 779cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "FLV no sequence end mode open\n"); 780cabdff1aSopenharmony_ci } else { 781cabdff1aSopenharmony_ci /* Add EOS tag */ 782cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 783cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[i]->codecpar; 784cabdff1aSopenharmony_ci FLVStreamContext *sc = s->streams[i]->priv_data; 785cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO && 786cabdff1aSopenharmony_ci (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4)) 787cabdff1aSopenharmony_ci put_avc_eos_tag(pb, sc->last_ts); 788cabdff1aSopenharmony_ci } 789cabdff1aSopenharmony_ci } 790cabdff1aSopenharmony_ci 791cabdff1aSopenharmony_ci file_size = avio_tell(pb); 792cabdff1aSopenharmony_ci 793cabdff1aSopenharmony_ci if (build_keyframes_idx) { 794cabdff1aSopenharmony_ci flv->datasize = file_size - flv->datastart_offset; 795cabdff1aSopenharmony_ci avio_seek(pb, flv->datasize_offset, SEEK_SET); 796cabdff1aSopenharmony_ci put_amf_double(pb, flv->datasize); 797cabdff1aSopenharmony_ci } 798cabdff1aSopenharmony_ci if (!(flv->flags & FLV_NO_METADATA)) { 799cabdff1aSopenharmony_ci if (!(flv->flags & FLV_NO_DURATION_FILESIZE)) { 800cabdff1aSopenharmony_ci /* update information */ 801cabdff1aSopenharmony_ci if (avio_seek(pb, flv->duration_offset, SEEK_SET) < 0) { 802cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Failed to update header with correct duration.\n"); 803cabdff1aSopenharmony_ci } else { 804cabdff1aSopenharmony_ci put_amf_double(pb, flv->duration / (double)1000); 805cabdff1aSopenharmony_ci } 806cabdff1aSopenharmony_ci if (avio_seek(pb, flv->filesize_offset, SEEK_SET) < 0) { 807cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Failed to update header with correct filesize.\n"); 808cabdff1aSopenharmony_ci } else { 809cabdff1aSopenharmony_ci put_amf_double(pb, file_size); 810cabdff1aSopenharmony_ci } 811cabdff1aSopenharmony_ci } 812cabdff1aSopenharmony_ci } 813cabdff1aSopenharmony_ci 814cabdff1aSopenharmony_ci return 0; 815cabdff1aSopenharmony_ci} 816cabdff1aSopenharmony_ci 817cabdff1aSopenharmony_cistatic int flv_write_packet(AVFormatContext *s, AVPacket *pkt) 818cabdff1aSopenharmony_ci{ 819cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 820cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; 821cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 822cabdff1aSopenharmony_ci FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data; 823cabdff1aSopenharmony_ci unsigned ts; 824cabdff1aSopenharmony_ci int size = pkt->size; 825cabdff1aSopenharmony_ci uint8_t *data = NULL; 826cabdff1aSopenharmony_ci int flags = -1, flags_size, ret = 0; 827cabdff1aSopenharmony_ci int64_t cur_offset = avio_tell(pb); 828cabdff1aSopenharmony_ci 829cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_AUDIO && !pkt->size) { 830cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Empty audio Packet\n"); 831cabdff1aSopenharmony_ci return AVERROR(EINVAL); 832cabdff1aSopenharmony_ci } 833cabdff1aSopenharmony_ci 834cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A || 835cabdff1aSopenharmony_ci par->codec_id == AV_CODEC_ID_VP6 || par->codec_id == AV_CODEC_ID_AAC) 836cabdff1aSopenharmony_ci flags_size = 2; 837cabdff1aSopenharmony_ci else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) 838cabdff1aSopenharmony_ci flags_size = 5; 839cabdff1aSopenharmony_ci else 840cabdff1aSopenharmony_ci flags_size = 1; 841cabdff1aSopenharmony_ci 842cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264 843cabdff1aSopenharmony_ci || par->codec_id == AV_CODEC_ID_MPEG4) { 844cabdff1aSopenharmony_ci size_t side_size; 845cabdff1aSopenharmony_ci uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); 846cabdff1aSopenharmony_ci if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) { 847cabdff1aSopenharmony_ci ret = ff_alloc_extradata(par, side_size); 848cabdff1aSopenharmony_ci if (ret < 0) 849cabdff1aSopenharmony_ci return ret; 850cabdff1aSopenharmony_ci memcpy(par->extradata, side, side_size); 851cabdff1aSopenharmony_ci flv_write_codec_header(s, par, pkt->dts); 852cabdff1aSopenharmony_ci } 853cabdff1aSopenharmony_ci } 854cabdff1aSopenharmony_ci 855cabdff1aSopenharmony_ci if (flv->delay == AV_NOPTS_VALUE) 856cabdff1aSopenharmony_ci flv->delay = -pkt->dts; 857cabdff1aSopenharmony_ci 858cabdff1aSopenharmony_ci if (pkt->dts < -flv->delay) { 859cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, 860cabdff1aSopenharmony_ci "Packets are not in the proper order with respect to DTS\n"); 861cabdff1aSopenharmony_ci return AVERROR(EINVAL); 862cabdff1aSopenharmony_ci } 863cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { 864cabdff1aSopenharmony_ci if (pkt->pts == AV_NOPTS_VALUE) { 865cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Packet is missing PTS\n"); 866cabdff1aSopenharmony_ci return AVERROR(EINVAL); 867cabdff1aSopenharmony_ci } 868cabdff1aSopenharmony_ci } 869cabdff1aSopenharmony_ci 870cabdff1aSopenharmony_ci ts = pkt->dts; 871cabdff1aSopenharmony_ci 872cabdff1aSopenharmony_ci if (s->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) { 873cabdff1aSopenharmony_ci write_metadata(s, ts); 874cabdff1aSopenharmony_ci s->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED; 875cabdff1aSopenharmony_ci } 876cabdff1aSopenharmony_ci 877cabdff1aSopenharmony_ci avio_write_marker(pb, av_rescale(ts, AV_TIME_BASE, 1000), 878cabdff1aSopenharmony_ci pkt->flags & AV_PKT_FLAG_KEY && (flv->video_par ? par->codec_type == AVMEDIA_TYPE_VIDEO : 1) ? AVIO_DATA_MARKER_SYNC_POINT : AVIO_DATA_MARKER_BOUNDARY_POINT); 879cabdff1aSopenharmony_ci 880cabdff1aSopenharmony_ci switch (par->codec_type) { 881cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 882cabdff1aSopenharmony_ci avio_w8(pb, FLV_TAG_TYPE_VIDEO); 883cabdff1aSopenharmony_ci 884cabdff1aSopenharmony_ci flags = ff_codec_get_tag(flv_video_codec_ids, par->codec_id); 885cabdff1aSopenharmony_ci 886cabdff1aSopenharmony_ci flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; 887cabdff1aSopenharmony_ci break; 888cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 889cabdff1aSopenharmony_ci flags = get_audio_flags(s, par); 890cabdff1aSopenharmony_ci 891cabdff1aSopenharmony_ci av_assert0(size); 892cabdff1aSopenharmony_ci 893cabdff1aSopenharmony_ci avio_w8(pb, FLV_TAG_TYPE_AUDIO); 894cabdff1aSopenharmony_ci break; 895cabdff1aSopenharmony_ci case AVMEDIA_TYPE_SUBTITLE: 896cabdff1aSopenharmony_ci case AVMEDIA_TYPE_DATA: 897cabdff1aSopenharmony_ci avio_w8(pb, FLV_TAG_TYPE_META); 898cabdff1aSopenharmony_ci break; 899cabdff1aSopenharmony_ci default: 900cabdff1aSopenharmony_ci return AVERROR(EINVAL); 901cabdff1aSopenharmony_ci } 902cabdff1aSopenharmony_ci 903cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { 904cabdff1aSopenharmony_ci /* check if extradata looks like mp4 formatted */ 905cabdff1aSopenharmony_ci if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1) 906cabdff1aSopenharmony_ci if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0) 907cabdff1aSopenharmony_ci return ret; 908cabdff1aSopenharmony_ci } else if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && 909cabdff1aSopenharmony_ci (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { 910cabdff1aSopenharmony_ci if (!s->streams[pkt->stream_index]->nb_frames) { 911cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: " 912cabdff1aSopenharmony_ci "use the audio bitstream filter 'aac_adtstoasc' to fix it " 913cabdff1aSopenharmony_ci "('-bsf:a aac_adtstoasc' option with ffmpeg)\n"); 914cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 915cabdff1aSopenharmony_ci } 916cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "aac bitstream error\n"); 917cabdff1aSopenharmony_ci } 918cabdff1aSopenharmony_ci 919cabdff1aSopenharmony_ci /* check Speex packet duration */ 920cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_SPEEX && ts - sc->last_ts > 160) 921cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Warning: Speex stream has more than " 922cabdff1aSopenharmony_ci "8 frames per packet. Adobe Flash " 923cabdff1aSopenharmony_ci "Player cannot handle this!\n"); 924cabdff1aSopenharmony_ci 925cabdff1aSopenharmony_ci if (sc->last_ts < ts) 926cabdff1aSopenharmony_ci sc->last_ts = ts; 927cabdff1aSopenharmony_ci 928cabdff1aSopenharmony_ci if (size + flags_size >= 1<<24) { 929cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Too large packet with size %u >= %u\n", 930cabdff1aSopenharmony_ci size + flags_size, 1<<24); 931cabdff1aSopenharmony_ci ret = AVERROR(EINVAL); 932cabdff1aSopenharmony_ci goto fail; 933cabdff1aSopenharmony_ci } 934cabdff1aSopenharmony_ci 935cabdff1aSopenharmony_ci avio_wb24(pb, size + flags_size); 936cabdff1aSopenharmony_ci put_timestamp(pb, ts); 937cabdff1aSopenharmony_ci avio_wb24(pb, flv->reserved); 938cabdff1aSopenharmony_ci 939cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_DATA || 940cabdff1aSopenharmony_ci par->codec_type == AVMEDIA_TYPE_SUBTITLE ) { 941cabdff1aSopenharmony_ci int data_size; 942cabdff1aSopenharmony_ci int64_t metadata_size_pos = avio_tell(pb); 943cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_TEXT) { 944cabdff1aSopenharmony_ci // legacy FFmpeg magic? 945cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_STRING); 946cabdff1aSopenharmony_ci put_amf_string(pb, "onTextData"); 947cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); 948cabdff1aSopenharmony_ci avio_wb32(pb, 2); 949cabdff1aSopenharmony_ci put_amf_string(pb, "type"); 950cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_STRING); 951cabdff1aSopenharmony_ci put_amf_string(pb, "Text"); 952cabdff1aSopenharmony_ci put_amf_string(pb, "text"); 953cabdff1aSopenharmony_ci avio_w8(pb, AMF_DATA_TYPE_STRING); 954cabdff1aSopenharmony_ci put_amf_string(pb, pkt->data); 955cabdff1aSopenharmony_ci put_amf_string(pb, ""); 956cabdff1aSopenharmony_ci avio_w8(pb, AMF_END_OF_OBJECT); 957cabdff1aSopenharmony_ci } else { 958cabdff1aSopenharmony_ci // just pass the metadata through 959cabdff1aSopenharmony_ci avio_write(pb, data ? data : pkt->data, size); 960cabdff1aSopenharmony_ci } 961cabdff1aSopenharmony_ci /* write total size of tag */ 962cabdff1aSopenharmony_ci data_size = avio_tell(pb) - metadata_size_pos; 963cabdff1aSopenharmony_ci avio_seek(pb, metadata_size_pos - 10, SEEK_SET); 964cabdff1aSopenharmony_ci avio_wb24(pb, data_size); 965cabdff1aSopenharmony_ci avio_seek(pb, data_size + 10 - 3, SEEK_CUR); 966cabdff1aSopenharmony_ci avio_wb32(pb, data_size + 11); 967cabdff1aSopenharmony_ci } else { 968cabdff1aSopenharmony_ci av_assert1(flags>=0); 969cabdff1aSopenharmony_ci avio_w8(pb,flags); 970cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_VP6) 971cabdff1aSopenharmony_ci avio_w8(pb,0); 972cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A) { 973cabdff1aSopenharmony_ci if (par->extradata_size) 974cabdff1aSopenharmony_ci avio_w8(pb, par->extradata[0]); 975cabdff1aSopenharmony_ci else 976cabdff1aSopenharmony_ci avio_w8(pb, ((FFALIGN(par->width, 16) - par->width) << 4) | 977cabdff1aSopenharmony_ci (FFALIGN(par->height, 16) - par->height)); 978cabdff1aSopenharmony_ci } else if (par->codec_id == AV_CODEC_ID_AAC) 979cabdff1aSopenharmony_ci avio_w8(pb, 1); // AAC raw 980cabdff1aSopenharmony_ci else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { 981cabdff1aSopenharmony_ci avio_w8(pb, 1); // AVC NALU 982cabdff1aSopenharmony_ci avio_wb24(pb, pkt->pts - pkt->dts); 983cabdff1aSopenharmony_ci } 984cabdff1aSopenharmony_ci 985cabdff1aSopenharmony_ci avio_write(pb, data ? data : pkt->data, size); 986cabdff1aSopenharmony_ci 987cabdff1aSopenharmony_ci avio_wb32(pb, size + flags_size + 11); // previous tag size 988cabdff1aSopenharmony_ci flv->duration = FFMAX(flv->duration, 989cabdff1aSopenharmony_ci pkt->pts + flv->delay + pkt->duration); 990cabdff1aSopenharmony_ci } 991cabdff1aSopenharmony_ci 992cabdff1aSopenharmony_ci if (flv->flags & FLV_ADD_KEYFRAME_INDEX) { 993cabdff1aSopenharmony_ci switch (par->codec_type) { 994cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 995cabdff1aSopenharmony_ci flv->videosize += (avio_tell(pb) - cur_offset); 996cabdff1aSopenharmony_ci flv->lasttimestamp = flv->acurframeindex / flv->framerate; 997cabdff1aSopenharmony_ci flv->acurframeindex++; 998cabdff1aSopenharmony_ci if (pkt->flags & AV_PKT_FLAG_KEY) { 999cabdff1aSopenharmony_ci double ts = flv->lasttimestamp; 1000cabdff1aSopenharmony_ci int64_t pos = cur_offset; 1001cabdff1aSopenharmony_ci 1002cabdff1aSopenharmony_ci flv->lastkeyframetimestamp = ts; 1003cabdff1aSopenharmony_ci flv->lastkeyframelocation = pos; 1004cabdff1aSopenharmony_ci ret = flv_append_keyframe_info(s, flv, ts, pos); 1005cabdff1aSopenharmony_ci if (ret < 0) 1006cabdff1aSopenharmony_ci goto fail; 1007cabdff1aSopenharmony_ci } 1008cabdff1aSopenharmony_ci break; 1009cabdff1aSopenharmony_ci 1010cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 1011cabdff1aSopenharmony_ci flv->audiosize += (avio_tell(pb) - cur_offset); 1012cabdff1aSopenharmony_ci break; 1013cabdff1aSopenharmony_ci 1014cabdff1aSopenharmony_ci default: 1015cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "par->codec_type is type = [%d]\n", par->codec_type); 1016cabdff1aSopenharmony_ci break; 1017cabdff1aSopenharmony_ci } 1018cabdff1aSopenharmony_ci } 1019cabdff1aSopenharmony_cifail: 1020cabdff1aSopenharmony_ci av_free(data); 1021cabdff1aSopenharmony_ci 1022cabdff1aSopenharmony_ci return ret; 1023cabdff1aSopenharmony_ci} 1024cabdff1aSopenharmony_ci 1025cabdff1aSopenharmony_cistatic int flv_check_bitstream(AVFormatContext *s, AVStream *st, 1026cabdff1aSopenharmony_ci const AVPacket *pkt) 1027cabdff1aSopenharmony_ci{ 1028cabdff1aSopenharmony_ci int ret = 1; 1029cabdff1aSopenharmony_ci 1030cabdff1aSopenharmony_ci if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { 1031cabdff1aSopenharmony_ci if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) 1032cabdff1aSopenharmony_ci ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL); 1033cabdff1aSopenharmony_ci } 1034cabdff1aSopenharmony_ci return ret; 1035cabdff1aSopenharmony_ci} 1036cabdff1aSopenharmony_ci 1037cabdff1aSopenharmony_cistatic void flv_deinit(AVFormatContext *s) 1038cabdff1aSopenharmony_ci{ 1039cabdff1aSopenharmony_ci FLVContext *flv = s->priv_data; 1040cabdff1aSopenharmony_ci FLVFileposition *filepos = flv->head_filepositions; 1041cabdff1aSopenharmony_ci 1042cabdff1aSopenharmony_ci while (filepos) { 1043cabdff1aSopenharmony_ci FLVFileposition *next = filepos->next; 1044cabdff1aSopenharmony_ci av_free(filepos); 1045cabdff1aSopenharmony_ci filepos = next; 1046cabdff1aSopenharmony_ci } 1047cabdff1aSopenharmony_ci flv->filepositions = flv->head_filepositions = NULL; 1048cabdff1aSopenharmony_ci flv->filepositions_count = 0; 1049cabdff1aSopenharmony_ci} 1050cabdff1aSopenharmony_ci 1051cabdff1aSopenharmony_cistatic const AVOption options[] = { 1052cabdff1aSopenharmony_ci { "flvflags", "FLV muxer flags", offsetof(FLVContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, 1053cabdff1aSopenharmony_ci { "aac_seq_header_detect", "Put AAC sequence header based on stream data", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_AAC_SEQ_HEADER_DETECT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, 1054cabdff1aSopenharmony_ci { "no_sequence_end", "disable sequence end for FLV", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_NO_SEQUENCE_END}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, 1055cabdff1aSopenharmony_ci { "no_metadata", "disable metadata for FLV", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_NO_METADATA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, 1056cabdff1aSopenharmony_ci { "no_duration_filesize", "disable duration and filesize zero value metadata for FLV", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_NO_DURATION_FILESIZE}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, 1057cabdff1aSopenharmony_ci { "add_keyframe_index", "Add keyframe index metadata", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_ADD_KEYFRAME_INDEX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, 1058cabdff1aSopenharmony_ci { NULL }, 1059cabdff1aSopenharmony_ci}; 1060cabdff1aSopenharmony_ci 1061cabdff1aSopenharmony_cistatic const AVClass flv_muxer_class = { 1062cabdff1aSopenharmony_ci .class_name = "flv muxer", 1063cabdff1aSopenharmony_ci .item_name = av_default_item_name, 1064cabdff1aSopenharmony_ci .option = options, 1065cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 1066cabdff1aSopenharmony_ci}; 1067cabdff1aSopenharmony_ci 1068cabdff1aSopenharmony_ciconst AVOutputFormat ff_flv_muxer = { 1069cabdff1aSopenharmony_ci .name = "flv", 1070cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"), 1071cabdff1aSopenharmony_ci .mime_type = "video/x-flv", 1072cabdff1aSopenharmony_ci .extensions = "flv", 1073cabdff1aSopenharmony_ci .priv_data_size = sizeof(FLVContext), 1074cabdff1aSopenharmony_ci .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF, 1075cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_FLV1, 1076cabdff1aSopenharmony_ci .init = flv_init, 1077cabdff1aSopenharmony_ci .write_header = flv_write_header, 1078cabdff1aSopenharmony_ci .write_packet = flv_write_packet, 1079cabdff1aSopenharmony_ci .write_trailer = flv_write_trailer, 1080cabdff1aSopenharmony_ci .deinit = flv_deinit, 1081cabdff1aSopenharmony_ci .check_bitstream= flv_check_bitstream, 1082cabdff1aSopenharmony_ci .codec_tag = (const AVCodecTag* const []) { 1083cabdff1aSopenharmony_ci flv_video_codec_ids, flv_audio_codec_ids, 0 1084cabdff1aSopenharmony_ci }, 1085cabdff1aSopenharmony_ci .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | 1086cabdff1aSopenharmony_ci AVFMT_TS_NONSTRICT, 1087cabdff1aSopenharmony_ci .priv_class = &flv_muxer_class, 1088cabdff1aSopenharmony_ci}; 1089