Mercurial > audlegacy-plugins
comparison src/ffmpeg/libavformat/flvenc.c @ 808:e8776388b02a trunk
[svn] - add ffmpeg
author | nenolod |
---|---|
date | Mon, 12 Mar 2007 11:18:54 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
807:0f9c8d4d3ac4 | 808:e8776388b02a |
---|---|
1 /* | |
2 * FLV encoder. | |
3 * Copyright (c) 2003 The FFmpeg Project. | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 #include "avformat.h" | |
22 | |
23 #undef NDEBUG | |
24 #include <assert.h> | |
25 | |
26 typedef struct FLVContext { | |
27 int hasAudio; | |
28 int hasVideo; | |
29 int reserved; | |
30 offset_t duration_offset; | |
31 offset_t filesize_offset; | |
32 int64_t duration; | |
33 } FLVContext; | |
34 | |
35 static int get_audio_flags(AVCodecContext *enc){ | |
36 int flags = (enc->bits_per_sample == 16) ? 0x2 : 0x0; | |
37 | |
38 switch (enc->sample_rate) { | |
39 case 44100: | |
40 flags |= 0x0C; | |
41 break; | |
42 case 22050: | |
43 flags |= 0x08; | |
44 break; | |
45 case 11025: | |
46 flags |= 0x04; | |
47 break; | |
48 case 8000: //nellymoser only | |
49 case 5512: //not mp3 | |
50 flags |= 0x00; | |
51 break; | |
52 default: | |
53 av_log(enc, AV_LOG_ERROR, "flv doesnt support that sample rate, choose from (44100, 22050, 11025)\n"); | |
54 return -1; | |
55 } | |
56 | |
57 if (enc->channels > 1) { | |
58 flags |= 0x01; | |
59 } | |
60 | |
61 switch(enc->codec_id){ | |
62 case CODEC_ID_MP3: | |
63 flags |= 0x20 | 0x2; | |
64 break; | |
65 case CODEC_ID_PCM_S8: | |
66 break; | |
67 case CODEC_ID_PCM_S16BE: | |
68 flags |= 0x60 | 0x2; | |
69 break; | |
70 case CODEC_ID_PCM_S16LE: | |
71 flags |= 0x2; | |
72 break; | |
73 case CODEC_ID_ADPCM_SWF: | |
74 flags |= 0x10; | |
75 break; | |
76 case 0: | |
77 flags |= enc->codec_tag<<4; | |
78 break; | |
79 default: | |
80 av_log(enc, AV_LOG_ERROR, "codec not compatible with flv\n"); | |
81 return -1; | |
82 } | |
83 | |
84 return flags; | |
85 } | |
86 | |
87 #define AMF_DOUBLE 0 | |
88 #define AMF_BOOLEAN 1 | |
89 #define AMF_STRING 2 | |
90 #define AMF_OBJECT 3 | |
91 #define AMF_MIXED_ARRAY 8 | |
92 #define AMF_ARRAY 10 | |
93 #define AMF_DATE 11 | |
94 | |
95 static void put_amf_string(ByteIOContext *pb, const char *str) | |
96 { | |
97 size_t len = strlen(str); | |
98 put_be16(pb, len); | |
99 put_buffer(pb, str, len); | |
100 } | |
101 | |
102 static void put_amf_double(ByteIOContext *pb, double d) | |
103 { | |
104 put_byte(pb, AMF_DOUBLE); | |
105 put_be64(pb, av_dbl2int(d)); | |
106 } | |
107 | |
108 static int flv_write_header(AVFormatContext *s) | |
109 { | |
110 ByteIOContext *pb = &s->pb; | |
111 FLVContext *flv = s->priv_data; | |
112 int i, width, height, samplerate; | |
113 double framerate = 0.0; | |
114 int metadata_size_pos, data_size; | |
115 | |
116 flv->hasAudio = 0; | |
117 flv->hasVideo = 0; | |
118 | |
119 put_tag(pb,"FLV"); | |
120 put_byte(pb,1); | |
121 put_byte(pb,0); // delayed write | |
122 put_be32(pb,9); | |
123 put_be32(pb,0); | |
124 | |
125 for(i=0; i<s->nb_streams; i++){ | |
126 AVCodecContext *enc = s->streams[i]->codec; | |
127 if (enc->codec_type == CODEC_TYPE_VIDEO) { | |
128 width = enc->width; | |
129 height = enc->height; | |
130 if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { | |
131 framerate = av_q2d(s->streams[i]->r_frame_rate); | |
132 } else { | |
133 framerate = 1/av_q2d(s->streams[i]->codec->time_base); | |
134 } | |
135 flv->hasVideo=1; | |
136 } else { | |
137 flv->hasAudio=1; | |
138 samplerate = enc->sample_rate; | |
139 } | |
140 av_set_pts_info(s->streams[i], 24, 1, 1000); /* 24 bit pts in ms */ | |
141 if(enc->codec_tag == 5){ | |
142 put_byte(pb,8); // message type | |
143 put_be24(pb,0); // include flags | |
144 put_be24(pb,0); // time stamp | |
145 put_be32(pb,0); // reserved | |
146 put_be32(pb,11); // size | |
147 flv->reserved=5; | |
148 } | |
149 if(enc->codec_type == CODEC_TYPE_AUDIO && get_audio_flags(enc)<0) | |
150 return -1; | |
151 } | |
152 | |
153 /* write meta_tag */ | |
154 put_byte(pb, 18); // tag type META | |
155 metadata_size_pos= url_ftell(pb); | |
156 put_be24(pb, 0); // size of data part (sum of all parts below) | |
157 put_be24(pb, 0); // time stamp | |
158 put_be32(pb, 0); // reserved | |
159 | |
160 /* now data of data_size size */ | |
161 | |
162 /* first event name as a string */ | |
163 put_byte(pb, AMF_STRING); // 1 byte | |
164 put_amf_string(pb, "onMetaData"); // 12 bytes | |
165 | |
166 /* mixed array (hash) with size and string/type/data tuples */ | |
167 put_byte(pb, AMF_MIXED_ARRAY); | |
168 put_be32(pb, 4*flv->hasVideo + flv->hasAudio + 2); // +2 for duration and file size | |
169 | |
170 put_amf_string(pb, "duration"); | |
171 flv->duration_offset= url_ftell(pb); | |
172 put_amf_double(pb, 0); // delayed write | |
173 | |
174 if(flv->hasVideo){ | |
175 put_amf_string(pb, "width"); | |
176 put_amf_double(pb, width); | |
177 | |
178 put_amf_string(pb, "height"); | |
179 put_amf_double(pb, height); | |
180 | |
181 put_amf_string(pb, "videodatarate"); | |
182 put_amf_double(pb, s->bit_rate / 1024.0); | |
183 | |
184 put_amf_string(pb, "framerate"); | |
185 put_amf_double(pb, framerate); | |
186 } | |
187 | |
188 if(flv->hasAudio){ | |
189 put_amf_string(pb, "audiosamplerate"); | |
190 put_amf_double(pb, samplerate); | |
191 } | |
192 | |
193 put_amf_string(pb, "filesize"); | |
194 flv->filesize_offset= url_ftell(pb); | |
195 put_amf_double(pb, 0); // delayed write | |
196 | |
197 put_amf_string(pb, ""); | |
198 put_byte(pb, 9); // end marker 1 byte | |
199 | |
200 /* write total size of tag */ | |
201 data_size= url_ftell(pb) - metadata_size_pos - 10; | |
202 url_fseek(pb, metadata_size_pos, SEEK_SET); | |
203 put_be24(pb, data_size); | |
204 url_fseek(pb, data_size + 10 - 3, SEEK_CUR); | |
205 put_be32(pb, data_size + 11); | |
206 | |
207 return 0; | |
208 } | |
209 | |
210 static int flv_write_trailer(AVFormatContext *s) | |
211 { | |
212 int64_t file_size; | |
213 int flags = 0; | |
214 | |
215 ByteIOContext *pb = &s->pb; | |
216 FLVContext *flv = s->priv_data; | |
217 | |
218 file_size = url_ftell(pb); | |
219 flags |= flv->hasAudio ? 4 : 0; | |
220 flags |= flv->hasVideo ? 1 : 0; | |
221 url_fseek(pb, 4, SEEK_SET); | |
222 put_byte(pb,flags); | |
223 | |
224 /* update informations */ | |
225 url_fseek(pb, flv->duration_offset, SEEK_SET); | |
226 put_amf_double(pb, flv->duration / (double)1000); | |
227 url_fseek(pb, flv->filesize_offset, SEEK_SET); | |
228 put_amf_double(pb, file_size); | |
229 | |
230 url_fseek(pb, file_size, SEEK_SET); | |
231 return 0; | |
232 } | |
233 | |
234 static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) | |
235 { | |
236 ByteIOContext *pb = &s->pb; | |
237 AVCodecContext *enc = s->streams[pkt->stream_index]->codec; | |
238 FLVContext *flv = s->priv_data; | |
239 int size= pkt->size; | |
240 int flags; | |
241 | |
242 // av_log(s, AV_LOG_DEBUG, "type:%d pts: %lld size:%d\n", enc->codec_type, timestamp, size); | |
243 | |
244 if (enc->codec_type == CODEC_TYPE_VIDEO) { | |
245 put_byte(pb, 9); | |
246 flags = 2; // choose h263 | |
247 flags |= pkt->flags & PKT_FLAG_KEY ? 0x10 : 0x20; // add keyframe indicator | |
248 } else { | |
249 assert(enc->codec_type == CODEC_TYPE_AUDIO); | |
250 flags = get_audio_flags(enc); | |
251 | |
252 assert(size); | |
253 | |
254 put_byte(pb, 8); | |
255 } | |
256 | |
257 put_be24(pb,size+1); // include flags | |
258 put_be24(pb,pkt->pts); | |
259 put_be32(pb,flv->reserved); | |
260 put_byte(pb,flags); | |
261 put_buffer(pb, pkt->data, size); | |
262 put_be32(pb,size+1+11); // previous tag size | |
263 flv->duration = pkt->pts + pkt->duration; | |
264 | |
265 put_flush_packet(pb); | |
266 return 0; | |
267 } | |
268 | |
269 AVOutputFormat flv_muxer = { | |
270 "flv", | |
271 "flv format", | |
272 "video/x-flv", | |
273 "flv", | |
274 sizeof(FLVContext), | |
275 #ifdef CONFIG_MP3LAME | |
276 CODEC_ID_MP3, | |
277 #else // CONFIG_MP3LAME | |
278 CODEC_ID_NONE, | |
279 #endif // CONFIG_MP3LAME | |
280 CODEC_ID_FLV1, | |
281 flv_write_header, | |
282 flv_write_packet, | |
283 flv_write_trailer, | |
284 }; |