Mercurial > libavformat.hg
annotate nutenc.c @ 3754:8d267b43eaba libavformat
Move malloc() down until after all initializations, so that the resource is
only allocated if initialization worked. This means that on failure, we
don't have to deallocate it.
author | rbultje |
---|---|
date | Sat, 23 Aug 2008 18:46:30 +0000 |
parents | e5b79592e187 |
children | 27537074f2a9 |
rev | line source |
---|---|
2324 | 1 /* |
2 * nut muxer | |
3 * Copyright (c) 2004-2007 Michael Niedermayer | |
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 | |
3286 | 22 #include "libavutil/tree.h" |
23 #include "libavcodec/mpegaudiodata.h" | |
2324 | 24 #include "nut.h" |
3046 | 25 |
26 static int find_expected_header(AVCodecContext *c, int size, int key_frame, uint8_t out[64]){ | |
27 int sample_rate= c->sample_rate; | |
28 | |
29 if(size>4096) | |
30 return 0; | |
31 | |
32 AV_WB24(out, 1); | |
33 | |
34 if(c->codec_id == CODEC_ID_MPEG4){ | |
35 if(key_frame){ | |
36 return 3; | |
37 }else{ | |
38 out[3]= 0xB6; | |
39 return 4; | |
40 } | |
41 }else if(c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MPEG2VIDEO){ | |
42 return 3; | |
43 }else if(c->codec_id == CODEC_ID_H264){ | |
44 return 3; | |
45 }else if(c->codec_id == CODEC_ID_MP3 || c->codec_id == CODEC_ID_MP2){ | |
46 int lsf, mpeg25, sample_rate_index, bitrate_index, frame_size; | |
47 int layer= c->codec_id == CODEC_ID_MP3 ? 3 : 2; | |
48 unsigned int header= 0xFFF00000; | |
49 | |
50 lsf = sample_rate < (24000+32000)/2; | |
51 mpeg25 = sample_rate < (12000+16000)/2; | |
52 sample_rate <<= lsf + mpeg25; | |
53 if (sample_rate < (32000 + 44100)/2) sample_rate_index=2; | |
54 else if(sample_rate < (44100 + 48000)/2) sample_rate_index=0; | |
55 else sample_rate_index=1; | |
56 | |
57 sample_rate= ff_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25); | |
58 | |
59 for(bitrate_index=2; bitrate_index<30; bitrate_index++){ | |
60 frame_size = ff_mpa_bitrate_tab[lsf][layer-1][bitrate_index>>1]; | |
61 frame_size = (frame_size * 144000) / (sample_rate << lsf) + (bitrate_index&1); | |
62 | |
63 if(frame_size == size) | |
64 break; | |
65 } | |
66 | |
67 header |= (!lsf)<<19; | |
68 header |= (4-layer)<<17; | |
69 header |= 1<<16; //no crc | |
70 AV_WB32(out, header); | |
71 if(size <= 0) | |
3135 | 72 return 2; //we guess there is no crc, if there is one the user clearly does not care about overhead |
3046 | 73 if(bitrate_index == 30) |
74 return -1; //something is wrong ... | |
75 | |
76 header |= (bitrate_index>>1)<<12; | |
77 header |= sample_rate_index<<10; | |
78 header |= (bitrate_index&1)<<9; | |
79 | |
80 return 2; //FIXME actually put the needed ones in build_elision_headers() | |
3135 | 81 return 3; //we guess that the private bit is not set |
82 //FIXME the above assumptions should be checked, if these turn out false too often something should be done | |
3046 | 83 } |
84 return 0; | |
85 } | |
86 | |
87 static int find_header_idx(AVFormatContext *s, AVCodecContext *c, int size, int frame_type){ | |
88 NUTContext *nut = s->priv_data; | |
89 uint8_t out[64]; | |
90 int i; | |
91 int len= find_expected_header(c, size, frame_type, out); | |
92 | |
93 //av_log(NULL, AV_LOG_ERROR, "expected_h len=%d size=%d codec_id=%d\n", len, size, c->codec_id); | |
94 | |
95 for(i=1; i<nut->header_count; i++){ | |
96 if( len == nut->header_len[i] | |
97 && !memcmp(out, nut->header[i], len)){ | |
98 // av_log(NULL, AV_LOG_ERROR, "found %d\n", i); | |
99 return i; | |
100 } | |
101 } | |
102 // av_log(NULL, AV_LOG_ERROR, "nothing found\n"); | |
103 return 0; | |
104 } | |
105 | |
106 static void build_elision_headers(AVFormatContext *s){ | |
107 NUTContext *nut = s->priv_data; | |
108 int i; | |
109 //FIXME this is lame | |
110 //FIXME write a 2pass mode to find the maximal headers | |
111 const static uint8_t headers[][5]={ | |
112 {3, 0x00, 0x00, 0x01}, | |
113 {4, 0x00, 0x00, 0x01, 0xB6}, | |
114 {2, 0xFF, 0xFA}, //mp3+crc | |
115 {2, 0xFF, 0xFB}, //mp3 | |
116 {2, 0xFF, 0xFC}, //mp2+crc | |
117 {2, 0xFF, 0xFD}, //mp2 | |
118 }; | |
119 | |
120 nut->header_count= 7; | |
121 for(i=1; i<nut->header_count; i++){ | |
122 nut->header_len[i]= headers[i-1][0]; | |
123 nut->header [i]= &headers[i-1][1]; | |
124 } | |
125 } | |
2324 | 126 |
127 static void build_frame_code(AVFormatContext *s){ | |
128 NUTContext *nut = s->priv_data; | |
129 int key_frame, index, pred, stream_id; | |
130 int start=1; | |
131 int end= 254; | |
132 int keyframe_0_esc= s->nb_streams > 2; | |
133 int pred_table[10]; | |
2339
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
134 FrameCode *ft; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
135 |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
136 ft= &nut->frame_code[start]; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
137 ft->flags= FLAG_CODED; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
138 ft->size_mul=1; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
139 ft->pts_delta=1; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
140 start++; |
2324 | 141 |
142 if(keyframe_0_esc){ | |
143 /* keyframe = 0 escape */ | |
144 FrameCode *ft= &nut->frame_code[start]; | |
145 ft->flags= FLAG_STREAM_ID | FLAG_SIZE_MSB | FLAG_CODED_PTS; | |
146 ft->size_mul=1; | |
147 start++; | |
148 } | |
149 | |
150 for(stream_id= 0; stream_id<s->nb_streams; stream_id++){ | |
151 int start2= start + (end-start)*stream_id / s->nb_streams; | |
152 int end2 = start + (end-start)*(stream_id+1) / s->nb_streams; | |
153 AVCodecContext *codec = s->streams[stream_id]->codec; | |
154 int is_audio= codec->codec_type == CODEC_TYPE_AUDIO; | |
155 int intra_only= /*codec->intra_only || */is_audio; | |
156 int pred_count; | |
157 | |
158 for(key_frame=0; key_frame<2; key_frame++){ | |
159 if(intra_only && keyframe_0_esc && key_frame==0) | |
160 continue; | |
161 | |
162 { | |
163 FrameCode *ft= &nut->frame_code[start2]; | |
164 ft->flags= FLAG_KEY*key_frame; | |
165 ft->flags|= FLAG_SIZE_MSB | FLAG_CODED_PTS; | |
166 ft->stream_id= stream_id; | |
167 ft->size_mul=1; | |
3046 | 168 if(is_audio) |
169 ft->header_idx= find_header_idx(s, codec, -1, key_frame); | |
2324 | 170 start2++; |
171 } | |
172 } | |
173 | |
174 key_frame= intra_only; | |
175 #if 1 | |
176 if(is_audio){ | |
177 int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate); | |
178 int pts; | |
179 for(pts=0; pts<2; pts++){ | |
180 for(pred=0; pred<2; pred++){ | |
181 FrameCode *ft= &nut->frame_code[start2]; | |
182 ft->flags= FLAG_KEY*key_frame; | |
183 ft->stream_id= stream_id; | |
184 ft->size_mul=frame_bytes + 2; | |
185 ft->size_lsb=frame_bytes + pred; | |
186 ft->pts_delta=pts; | |
3046 | 187 ft->header_idx= find_header_idx(s, codec, frame_bytes + pred, key_frame); |
2324 | 188 start2++; |
189 } | |
190 } | |
191 }else{ | |
192 FrameCode *ft= &nut->frame_code[start2]; | |
193 ft->flags= FLAG_KEY | FLAG_SIZE_MSB; | |
194 ft->stream_id= stream_id; | |
195 ft->size_mul=1; | |
196 ft->pts_delta=1; | |
197 start2++; | |
198 } | |
199 #endif | |
200 | |
201 if(codec->has_b_frames){ | |
202 pred_count=5; | |
203 pred_table[0]=-2; | |
204 pred_table[1]=-1; | |
205 pred_table[2]=1; | |
206 pred_table[3]=3; | |
207 pred_table[4]=4; | |
208 }else if(codec->codec_id == CODEC_ID_VORBIS){ | |
209 pred_count=3; | |
210 pred_table[0]=2; | |
211 pred_table[1]=9; | |
212 pred_table[2]=16; | |
213 }else{ | |
214 pred_count=1; | |
215 pred_table[0]=1; | |
216 } | |
217 | |
218 for(pred=0; pred<pred_count; pred++){ | |
219 int start3= start2 + (end2-start2)*pred / pred_count; | |
220 int end3 = start2 + (end2-start2)*(pred+1) / pred_count; | |
221 | |
222 for(index=start3; index<end3; index++){ | |
223 FrameCode *ft= &nut->frame_code[index]; | |
224 ft->flags= FLAG_KEY*key_frame; | |
225 ft->flags|= FLAG_SIZE_MSB; | |
226 ft->stream_id= stream_id; | |
227 //FIXME use single byte size and pred from last | |
228 ft->size_mul= end3-start3; | |
229 ft->size_lsb= index - start3; | |
230 ft->pts_delta= pred_table[pred]; | |
3046 | 231 if(is_audio) |
232 ft->header_idx= find_header_idx(s, codec, -1, key_frame); | |
2324 | 233 } |
234 } | |
235 } | |
236 memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N')); | |
237 nut->frame_code[ 0].flags= | |
238 nut->frame_code[255].flags= | |
239 nut->frame_code['N'].flags= FLAG_INVALID; | |
240 } | |
241 | |
242 /** | |
243 * Gets the length in bytes which is needed to store val as v. | |
244 */ | |
245 static int get_length(uint64_t val){ | |
246 int i=1; | |
247 | |
248 while(val>>=7) | |
249 i++; | |
250 | |
251 return i; | |
252 } | |
253 | |
254 static void put_v(ByteIOContext *bc, uint64_t val){ | |
255 int i= get_length(val); | |
256 | |
257 while(--i>0) | |
258 put_byte(bc, 128 | (val>>(7*i))); | |
259 | |
260 put_byte(bc, val&127); | |
261 } | |
262 | |
2342 | 263 static void put_t(NUTContext *nut, StreamContext *nus, ByteIOContext *bc, uint64_t val){ |
264 val *= nut->time_base_count; | |
265 val += nus->time_base - nut->time_base; | |
266 put_v(bc, val); | |
267 } | |
268 | |
2324 | 269 /** |
2393 | 270 * Stores a string as vb. |
2324 | 271 */ |
272 static void put_str(ByteIOContext *bc, const char *string){ | |
273 int len= strlen(string); | |
274 | |
275 put_v(bc, len); | |
276 put_buffer(bc, string, len); | |
277 } | |
278 | |
279 static void put_s(ByteIOContext *bc, int64_t val){ | |
280 put_v(bc, 2*FFABS(val) - (val>0)); | |
281 } | |
282 | |
283 #ifdef TRACE | |
284 static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ | |
2344 | 285 av_log(NULL, AV_LOG_DEBUG, "put_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); |
2324 | 286 |
287 put_v(bc, v); | |
288 } | |
289 | |
290 static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){ | |
2344 | 291 av_log(NULL, AV_LOG_DEBUG, "put_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); |
2324 | 292 |
293 put_s(bc, v); | |
294 } | |
295 #define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
296 #define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
297 #endif | |
298 | |
2340 | 299 //FIXME remove calculate_checksum |
2347 | 300 static void put_packet(NUTContext *nut, ByteIOContext *bc, ByteIOContext *dyn_bc, int calculate_checksum, uint64_t startcode){ |
2331
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
301 uint8_t *dyn_buf=NULL; |
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
302 int dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf); |
2332 | 303 int forw_ptr= dyn_size + 4*calculate_checksum; |
2324 | 304 |
2332 | 305 if(forw_ptr > 4096) |
2683
153d6efc05b8
rename av_crc04C11DB7_update to ff_crc04C11DB7_update and move it to aviobuf.c so it can be reused by other (de)muxers
bcoudurier
parents:
2393
diff
changeset
|
306 init_checksum(bc, ff_crc04C11DB7_update, 0); |
2347 | 307 put_be64(bc, startcode); |
2332 | 308 put_v(bc, forw_ptr); |
309 if(forw_ptr > 4096) | |
310 put_le32(bc, get_checksum(bc)); | |
311 | |
2324 | 312 if(calculate_checksum) |
2683
153d6efc05b8
rename av_crc04C11DB7_update to ff_crc04C11DB7_update and move it to aviobuf.c so it can be reused by other (de)muxers
bcoudurier
parents:
2393
diff
changeset
|
313 init_checksum(bc, ff_crc04C11DB7_update, 0); |
2331
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
314 put_buffer(bc, dyn_buf, dyn_size); |
2324 | 315 if(calculate_checksum) |
2331
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
316 put_le32(bc, get_checksum(bc)); |
2324 | 317 |
2331
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
318 av_free(dyn_buf); |
2324 | 319 } |
320 | |
2329 | 321 static void write_mainheader(NUTContext *nut, ByteIOContext *bc){ |
3046 | 322 int i, j, tmp_pts, tmp_flags, tmp_stream, tmp_mul, tmp_size, tmp_fields, tmp_head_idx; |
323 int64_t tmp_match; | |
2324 | 324 |
2360
b2eeaa4df665
muxer should now be spec compliant (though it likely still contains bugs!)
michael
parents:
2359
diff
changeset
|
325 put_v(bc, 3); /* version */ |
2329 | 326 put_v(bc, nut->avf->nb_streams); |
3014
66fb9d4dea91
nut->max_distance was not set at all anywhere in the NUT muxer
ods15
parents:
3004
diff
changeset
|
327 put_v(bc, nut->max_distance); |
2324 | 328 put_v(bc, nut->time_base_count); |
329 | |
330 for(i=0; i<nut->time_base_count; i++){ | |
331 put_v(bc, nut->time_base[i].num); | |
332 put_v(bc, nut->time_base[i].den); | |
333 } | |
334 | |
335 tmp_pts=0; | |
336 tmp_mul=1; | |
337 tmp_stream=0; | |
3046 | 338 tmp_match= 1-(1LL<<62); |
339 tmp_head_idx= 0; | |
2324 | 340 for(i=0; i<256;){ |
341 tmp_fields=0; | |
342 tmp_size=0; | |
343 // tmp_res=0; | |
344 if(tmp_pts != nut->frame_code[i].pts_delta) tmp_fields=1; | |
345 if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2; | |
346 if(tmp_stream != nut->frame_code[i].stream_id) tmp_fields=3; | |
347 if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4; | |
348 // if(tmp_res != nut->frame_code[i].res ) tmp_fields=5; | |
3046 | 349 if(tmp_head_idx!=nut->frame_code[i].header_idx)tmp_fields=8; |
2324 | 350 |
351 tmp_pts = nut->frame_code[i].pts_delta; | |
352 tmp_flags = nut->frame_code[i].flags; | |
353 tmp_stream= nut->frame_code[i].stream_id; | |
354 tmp_mul = nut->frame_code[i].size_mul; | |
355 tmp_size = nut->frame_code[i].size_lsb; | |
356 // tmp_res = nut->frame_code[i].res; | |
3046 | 357 tmp_head_idx= nut->frame_code[i].header_idx; |
2324 | 358 |
359 for(j=0; i<256; j++,i++){ | |
360 if(i == 'N'){ | |
361 j--; | |
362 continue; | |
363 } | |
364 if(nut->frame_code[i].pts_delta != tmp_pts ) break; | |
365 if(nut->frame_code[i].flags != tmp_flags ) break; | |
366 if(nut->frame_code[i].stream_id != tmp_stream) break; | |
367 if(nut->frame_code[i].size_mul != tmp_mul ) break; | |
368 if(nut->frame_code[i].size_lsb != tmp_size+j) break; | |
369 // if(nut->frame_code[i].res != tmp_res ) break; | |
3046 | 370 if(nut->frame_code[i].header_idx!= tmp_head_idx) break; |
2324 | 371 } |
372 if(j != tmp_mul - tmp_size) tmp_fields=6; | |
373 | |
374 put_v(bc, tmp_flags); | |
375 put_v(bc, tmp_fields); | |
376 if(tmp_fields>0) put_s(bc, tmp_pts); | |
377 if(tmp_fields>1) put_v(bc, tmp_mul); | |
378 if(tmp_fields>2) put_v(bc, tmp_stream); | |
379 if(tmp_fields>3) put_v(bc, tmp_size); | |
380 if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/); | |
381 if(tmp_fields>5) put_v(bc, j); | |
3046 | 382 if(tmp_fields>6) put_v(bc, tmp_match); |
383 if(tmp_fields>7) put_v(bc, tmp_head_idx); | |
384 } | |
385 put_v(bc, nut->header_count-1); | |
386 for(i=1; i<nut->header_count; i++){ | |
387 put_v(bc, nut->header_len[i]); | |
388 put_buffer(bc, nut->header[i], nut->header_len[i]); | |
2324 | 389 } |
2329 | 390 } |
2324 | 391 |
2330 | 392 static int write_streamheader(NUTContext *nut, ByteIOContext *bc, AVCodecContext *codec, int i){ |
393 put_v(bc, i); | |
394 switch(codec->codec_type){ | |
395 case CODEC_TYPE_VIDEO: put_v(bc, 0); break; | |
396 case CODEC_TYPE_AUDIO: put_v(bc, 1); break; | |
3101 | 397 case CODEC_TYPE_SUBTITLE: put_v(bc, 2); break; |
2330 | 398 default : put_v(bc, 3); break; |
399 } | |
400 put_v(bc, 4); | |
401 if (codec->codec_tag){ | |
402 put_le32(bc, codec->codec_tag); | |
403 }else | |
404 return -1; | |
405 | |
2341 | 406 put_v(bc, nut->stream[i].time_base - nut->time_base); |
2330 | 407 put_v(bc, nut->stream[i].msb_pts_shift); |
408 put_v(bc, nut->stream[i].max_pts_distance); | |
409 put_v(bc, codec->has_b_frames); | |
410 put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ | |
411 | |
412 put_v(bc, codec->extradata_size); | |
413 put_buffer(bc, codec->extradata, codec->extradata_size); | |
414 | |
415 switch(codec->codec_type){ | |
416 case CODEC_TYPE_AUDIO: | |
417 put_v(bc, codec->sample_rate); | |
418 put_v(bc, 1); | |
419 put_v(bc, codec->channels); | |
420 break; | |
421 case CODEC_TYPE_VIDEO: | |
422 put_v(bc, codec->width); | |
423 put_v(bc, codec->height); | |
2363 | 424 |
425 if(codec->sample_aspect_ratio.num<=0 || codec->sample_aspect_ratio.den<=0){ | |
426 put_v(bc, 0); | |
427 put_v(bc, 0); | |
428 }else{ | |
429 put_v(bc, codec->sample_aspect_ratio.num); | |
430 put_v(bc, codec->sample_aspect_ratio.den); | |
431 } | |
2330 | 432 put_v(bc, 0); /* csp type -- unknown */ |
433 break; | |
434 default: | |
435 break; | |
436 } | |
437 return 0; | |
438 } | |
439 | |
3004 | 440 static int add_info(ByteIOContext *bc, const char *type, const char *value){ |
2358 | 441 put_str(bc, type); |
442 put_s(bc, -1); | |
443 put_str(bc, value); | |
444 return 1; | |
445 } | |
446 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
447 static int write_globalinfo(NUTContext *nut, ByteIOContext *bc){ |
2358 | 448 AVFormatContext *s= nut->avf; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
449 ByteIOContext *dyn_bc; |
2358 | 450 uint8_t *dyn_buf=NULL; |
451 int count=0, dyn_size; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
452 int ret = url_open_dyn_buf(&dyn_bc); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
453 if(ret < 0) |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
454 return ret; |
2358 | 455 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
456 if(s->title [0]) count+= add_info(dyn_bc, "Title" , s->title); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
457 if(s->author [0]) count+= add_info(dyn_bc, "Author" , s->author); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
458 if(s->copyright[0]) count+= add_info(dyn_bc, "Copyright", s->copyright); |
2358 | 459 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
460 count+= add_info(dyn_bc, "Encoder" , LIBAVFORMAT_IDENT); |
2358 | 461 |
462 put_v(bc, 0); //stream_if_plus1 | |
463 put_v(bc, 0); //chapter_id | |
464 put_v(bc, 0); //timestamp_start | |
465 put_v(bc, 0); //length | |
466 | |
467 put_v(bc, count); | |
468 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
469 dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf); |
2358 | 470 put_buffer(bc, dyn_buf, dyn_size); |
471 av_free(dyn_buf); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
472 return 0; |
2358 | 473 } |
474 | |
3120
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
475 static int write_streaminfo(NUTContext *nut, ByteIOContext *bc, int stream_id){ |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
476 AVFormatContext *s= nut->avf; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
477 AVStream* st = s->streams[stream_id]; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
478 ByteIOContext *dyn_bc; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
479 uint8_t *dyn_buf=NULL; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
480 int count=0, dyn_size, i; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
481 int ret = url_open_dyn_buf(&dyn_bc); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
482 if(ret < 0) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
483 return ret; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
484 |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
485 for (i=0; ff_nut_dispositions[i].flag; ++i) { |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
486 if (st->disposition & ff_nut_dispositions[i].flag) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
487 count += add_info(dyn_bc, "Disposition", ff_nut_dispositions[i].str); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
488 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
489 dyn_size = url_close_dyn_buf(dyn_bc, &dyn_buf); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
490 |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
491 if (count) { |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
492 put_v(bc, stream_id + 1); //stream_id_plus1 |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
493 put_v(bc, 0); //chapter_id |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
494 put_v(bc, 0); //timestamp_start |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
495 put_v(bc, 0); //length |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
496 |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
497 put_v(bc, count); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
498 |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
499 put_buffer(bc, dyn_buf, dyn_size); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
500 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
501 |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
502 av_free(dyn_buf); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
503 return count; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
504 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
505 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
506 static int write_headers(NUTContext *nut, ByteIOContext *bc){ |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
507 ByteIOContext *dyn_bc; |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
508 int i, ret; |
2345 | 509 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
510 ret = url_open_dyn_buf(&dyn_bc); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
511 if(ret < 0) |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
512 return ret; |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
513 write_mainheader(nut, dyn_bc); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
514 put_packet(nut, bc, dyn_bc, 1, MAIN_STARTCODE); |
2345 | 515 |
516 for (i=0; i < nut->avf->nb_streams; i++){ | |
517 AVCodecContext *codec = nut->avf->streams[i]->codec; | |
518 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
519 ret = url_open_dyn_buf(&dyn_bc); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
520 if(ret < 0) |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
521 return ret; |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
522 write_streamheader(nut, dyn_bc, codec, i); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
523 put_packet(nut, bc, dyn_bc, 1, STREAM_STARTCODE); |
2345 | 524 } |
2358 | 525 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
526 ret = url_open_dyn_buf(&dyn_bc); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
527 if(ret < 0) |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
528 return ret; |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
529 write_globalinfo(nut, dyn_bc); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
530 put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE); |
2359 | 531 |
3120
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
532 for (i = 0; i < nut->avf->nb_streams; i++) { |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
533 ret = url_open_dyn_buf(&dyn_bc); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
534 if(ret < 0) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
535 return ret; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
536 ret = write_streaminfo(nut, dyn_bc, i); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
537 if (ret < 0) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
538 return ret; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
539 if (ret > 0) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
540 put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
541 else { |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
542 uint8_t* buf; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
543 url_close_dyn_buf(dyn_bc, &buf); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
544 av_free(buf); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
545 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
546 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
547 |
2359 | 548 nut->last_syncpoint_pos= INT_MIN; |
549 nut->header_count++; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
550 return 0; |
2345 | 551 } |
552 | |
2329 | 553 static int write_header(AVFormatContext *s){ |
554 NUTContext *nut = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
555 ByteIOContext *bc = s->pb; |
2329 | 556 int i, j; |
557 | |
558 nut->avf= s; | |
559 | |
560 nut->stream = av_mallocz(sizeof(StreamContext)*s->nb_streams); | |
561 nut->time_base= av_mallocz(sizeof(AVRational )*s->nb_streams); | |
562 | |
563 for(i=0; i<s->nb_streams; i++){ | |
564 AVStream *st= s->streams[i]; | |
565 int ssize; | |
566 AVRational time_base; | |
567 ff_parse_specific_params(st->codec, &time_base.den, &ssize, &time_base.num); | |
568 | |
569 av_set_pts_info(st, 64, time_base.num, time_base.den); | |
570 | |
571 for(j=0; j<nut->time_base_count; j++){ | |
572 if(!memcmp(&time_base, &nut->time_base[j], sizeof(AVRational))){ | |
573 break; | |
574 } | |
575 } | |
576 nut->time_base[j]= time_base; | |
577 nut->stream[i].time_base= &nut->time_base[j]; | |
578 if(j==nut->time_base_count) | |
579 nut->time_base_count++; | |
580 | |
581 if(av_q2d(time_base) >= 0.001) | |
582 nut->stream[i].msb_pts_shift = 7; | |
583 else | |
584 nut->stream[i].msb_pts_shift = 14; | |
585 nut->stream[i].max_pts_distance= FFMAX(1/av_q2d(time_base), 1); | |
586 } | |
587 | |
3014
66fb9d4dea91
nut->max_distance was not set at all anywhere in the NUT muxer
ods15
parents:
3004
diff
changeset
|
588 nut->max_distance = MAX_DISTANCE; |
3046 | 589 build_elision_headers(s); |
2329 | 590 build_frame_code(s); |
591 assert(nut->frame_code['N'].flags == FLAG_INVALID); | |
592 | |
593 put_buffer(bc, ID_STRING, strlen(ID_STRING)); | |
594 put_byte(bc, 0); | |
595 | |
2345 | 596 write_headers(nut, bc); |
2325 | 597 |
2324 | 598 put_flush_packet(bc); |
599 | |
2359 | 600 //FIXME index |
2324 | 601 |
602 return 0; | |
603 } | |
604 | |
2343 | 605 static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc, AVPacket *pkt){ |
606 int flags= 0; | |
607 | |
608 if(pkt->flags & PKT_FLAG_KEY ) flags |= FLAG_KEY; | |
609 if(pkt->stream_index != fc->stream_id ) flags |= FLAG_STREAM_ID; | |
610 if(pkt->size / fc->size_mul ) flags |= FLAG_SIZE_MSB; | |
611 if(pkt->pts - nus->last_pts != fc->pts_delta) flags |= FLAG_CODED_PTS; | |
612 if(pkt->size > 2*nut->max_distance ) flags |= FLAG_CHECKSUM; | |
613 if(FFABS(pkt->pts - nus->last_pts) | |
614 > nus->max_pts_distance) flags |= FLAG_CHECKSUM; | |
3046 | 615 if( pkt->size < nut->header_len[fc->header_idx] |
616 || (pkt->size > 4096 && fc->header_idx) | |
617 || memcmp(pkt->data, nut->header[fc->header_idx], nut->header_len[fc->header_idx])) | |
618 flags |= FLAG_HEADER_IDX; | |
2343 | 619 |
2371 | 620 return flags | (fc->flags & FLAG_CODED); |
2343 | 621 } |
622 | |
3046 | 623 static int find_best_header_idx(NUTContext *nut, AVPacket *pkt){ |
624 int i; | |
625 int best_i = 0; | |
626 int best_len= 0; | |
627 | |
628 if(pkt->size > 4096) | |
629 return 0; | |
630 | |
631 for(i=1; i<nut->header_count; i++){ | |
632 if( pkt->size >= nut->header_len[i] | |
633 && nut->header_len[i] > best_len | |
634 && !memcmp(pkt->data, nut->header[i], nut->header_len[i])){ | |
635 best_i= i; | |
636 best_len= nut->header_len[i]; | |
637 } | |
638 } | |
639 return best_i; | |
640 } | |
641 | |
2324 | 642 static int write_packet(AVFormatContext *s, AVPacket *pkt){ |
2343 | 643 NUTContext *nut = s->priv_data; |
644 StreamContext *nus= &nut->stream[pkt->stream_index]; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
645 ByteIOContext *bc = s->pb, *dyn_bc; |
2343 | 646 FrameCode *fc; |
647 int64_t coded_pts; | |
3046 | 648 int best_length, frame_code, flags, needed_flags, i, header_idx, best_header_idx; |
2343 | 649 int key_frame = !!(pkt->flags & PKT_FLAG_KEY); |
650 int store_sp=0; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
651 int ret; |
2343 | 652 |
3508 | 653 if(pkt->pts < 0) |
654 return -1; | |
655 | |
2359 | 656 if(1LL<<(20+3*nut->header_count) <= url_ftell(bc)) |
657 write_headers(nut, bc); | |
658 | |
3015
db8d14740060
Fix intented algo in syncpoint writing before keyframes in NUT muxer
ods15
parents:
3014
diff
changeset
|
659 if(key_frame && !(nus->last_flags & FLAG_KEY)) |
2343 | 660 store_sp= 1; |
661 | |
662 if(pkt->size + 30/*FIXME check*/ + url_ftell(bc) >= nut->last_syncpoint_pos + nut->max_distance) | |
663 store_sp= 1; | |
664 | |
2393 | 665 //FIXME: Ensure store_sp is 1 in the first place. |
2343 | 666 |
667 if(store_sp){ | |
2350 | 668 syncpoint_t *sp, dummy= {.pos= INT64_MAX}; |
669 | |
2343 | 670 ff_nut_reset_ts(nut, *nus->time_base, pkt->dts); |
2350 | 671 for(i=0; i<s->nb_streams; i++){ |
672 AVStream *st= s->streams[i]; | |
3016
eac2648449a5
back_ptr calculation used wrong timebase when searching for back syncpoint
ods15
parents:
3015
diff
changeset
|
673 int64_t dts_tb = av_rescale_rnd(pkt->dts, |
eac2648449a5
back_ptr calculation used wrong timebase when searching for back syncpoint
ods15
parents:
3015
diff
changeset
|
674 nus->time_base->num * (int64_t)nut->stream[i].time_base->den, |
eac2648449a5
back_ptr calculation used wrong timebase when searching for back syncpoint
ods15
parents:
3015
diff
changeset
|
675 nus->time_base->den * (int64_t)nut->stream[i].time_base->num, |
eac2648449a5
back_ptr calculation used wrong timebase when searching for back syncpoint
ods15
parents:
3015
diff
changeset
|
676 AV_ROUND_DOWN); |
eac2648449a5
back_ptr calculation used wrong timebase when searching for back syncpoint
ods15
parents:
3015
diff
changeset
|
677 int index= av_index_search_timestamp(st, dts_tb, AVSEEK_FLAG_BACKWARD); |
2939 | 678 if(index>=0) dummy.pos= FFMIN(dummy.pos, st->index_entries[index].pos); |
2350 | 679 } |
2939 | 680 if(dummy.pos == INT64_MAX) |
681 dummy.pos= 0; | |
2350 | 682 sp= av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, NULL); |
2343 | 683 |
684 nut->last_syncpoint_pos= url_ftell(bc); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
685 ret = url_open_dyn_buf(&dyn_bc); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
686 if(ret < 0) |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
687 return ret; |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
688 put_t(nut, nus, dyn_bc, pkt->dts); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
689 put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos)>>4 : 0); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
690 put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE); |
2350 | 691 |
692 ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0/*unused*/, pkt->dts); | |
2343 | 693 } |
694 assert(nus->last_pts != AV_NOPTS_VALUE); | |
695 | |
696 coded_pts = pkt->pts & ((1<<nus->msb_pts_shift)-1); | |
697 if(ff_lsb2full(nus, coded_pts) != pkt->pts) | |
698 coded_pts= pkt->pts + (1<<nus->msb_pts_shift); | |
699 | |
3046 | 700 best_header_idx= find_best_header_idx(nut, pkt); |
701 | |
2343 | 702 best_length=INT_MAX; |
703 frame_code= -1; | |
704 for(i=0; i<256; i++){ | |
705 int length= 0; | |
706 FrameCode *fc= &nut->frame_code[i]; | |
707 int flags= fc->flags; | |
708 | |
709 if(flags & FLAG_INVALID) | |
710 continue; | |
711 needed_flags= get_needed_flags(nut, nus, fc, pkt); | |
712 | |
713 if(flags & FLAG_CODED){ | |
714 length++; | |
2372 | 715 flags = needed_flags; |
2343 | 716 } |
717 | |
718 if((flags & needed_flags) != needed_flags) | |
719 continue; | |
720 | |
721 if((flags ^ needed_flags) & FLAG_KEY) | |
722 continue; | |
723 | |
724 if(flags & FLAG_STREAM_ID) | |
725 length+= get_length(pkt->stream_index); | |
726 | |
727 if(pkt->size % fc->size_mul != fc->size_lsb) | |
728 continue; | |
729 if(flags & FLAG_SIZE_MSB) | |
730 length += get_length(pkt->size / fc->size_mul); | |
731 | |
732 if(flags & FLAG_CHECKSUM) | |
733 length+=4; | |
734 | |
735 if(flags & FLAG_CODED_PTS) | |
736 length += get_length(coded_pts); | |
737 | |
3046 | 738 if( (flags & FLAG_CODED) |
739 && nut->header_len[best_header_idx] > nut->header_len[fc->header_idx]+1){ | |
740 flags |= FLAG_HEADER_IDX; | |
741 } | |
742 | |
743 if(flags & FLAG_HEADER_IDX){ | |
744 length += 1 - nut->header_len[best_header_idx]; | |
745 }else{ | |
746 length -= nut->header_len[fc->header_idx]; | |
747 } | |
748 | |
2343 | 749 length*=4; |
750 length+= !(flags & FLAG_CODED_PTS); | |
751 length+= !(flags & FLAG_CHECKSUM); | |
752 | |
753 if(length < best_length){ | |
754 best_length= length; | |
755 frame_code=i; | |
756 } | |
757 } | |
758 assert(frame_code != -1); | |
759 fc= &nut->frame_code[frame_code]; | |
760 flags= fc->flags; | |
761 needed_flags= get_needed_flags(nut, nus, fc, pkt); | |
3046 | 762 header_idx= fc->header_idx; |
2343 | 763 |
2683
153d6efc05b8
rename av_crc04C11DB7_update to ff_crc04C11DB7_update and move it to aviobuf.c so it can be reused by other (de)muxers
bcoudurier
parents:
2393
diff
changeset
|
764 init_checksum(bc, ff_crc04C11DB7_update, 0); |
2343 | 765 put_byte(bc, frame_code); |
766 if(flags & FLAG_CODED){ | |
767 put_v(bc, (flags^needed_flags) & ~(FLAG_CODED)); | |
768 flags = needed_flags; | |
769 } | |
770 if(flags & FLAG_STREAM_ID) put_v(bc, pkt->stream_index); | |
771 if(flags & FLAG_CODED_PTS) put_v(bc, coded_pts); | |
772 if(flags & FLAG_SIZE_MSB) put_v(bc, pkt->size / fc->size_mul); | |
3046 | 773 if(flags & FLAG_HEADER_IDX) put_v(bc, header_idx= best_header_idx); |
2343 | 774 |
775 if(flags & FLAG_CHECKSUM) put_le32(bc, get_checksum(bc)); | |
776 else get_checksum(bc); | |
777 | |
3046 | 778 put_buffer(bc, pkt->data + nut->header_len[header_idx], pkt->size - nut->header_len[header_idx]); |
2343 | 779 nus->last_flags= flags; |
3047 | 780 nus->last_pts= pkt->pts; |
2350 | 781 |
782 //FIXME just store one per syncpoint | |
783 if(flags & FLAG_KEY) | |
784 av_add_index_entry( | |
785 s->streams[pkt->stream_index], | |
786 nut->last_syncpoint_pos, | |
787 pkt->pts, | |
788 0, | |
789 0, | |
790 AVINDEX_KEYFRAME); | |
791 | |
2324 | 792 return 0; |
793 } | |
794 | |
2346
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
795 static int write_trailer(AVFormatContext *s){ |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
796 NUTContext *nut= s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2683
diff
changeset
|
797 ByteIOContext *bc= s->pb; |
2346
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
798 |
2359 | 799 while(nut->header_count<3) |
800 write_headers(nut, bc); | |
2346
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
801 put_flush_packet(bc); |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
802 |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
803 return 0; |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
804 } |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
805 |
2324 | 806 AVOutputFormat nut_muxer = { |
807 "nut", | |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3286
diff
changeset
|
808 NULL_IF_CONFIG_SMALL("NUT format"), |
2324 | 809 "video/x-nut", |
810 "nut", | |
811 sizeof(NUTContext), | |
812 #ifdef CONFIG_LIBVORBIS | |
813 CODEC_ID_VORBIS, | |
814 #elif defined(CONFIG_LIBMP3LAME) | |
815 CODEC_ID_MP3, | |
816 #else | |
3623 | 817 CODEC_ID_MP2, |
2324 | 818 #endif |
819 CODEC_ID_MPEG4, | |
820 write_header, | |
821 write_packet, | |
2346
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
822 write_trailer, |
2324 | 823 .flags = AVFMT_GLOBALHEADER, |
3112 | 824 .codec_tag= (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, ff_nut_subtitle_tags, 0}, |
2324 | 825 }; |