Mercurial > libavformat.hg
annotate nutenc.c @ 2400:fcaecfb05781 libavformat
When looking for the last packet in each
stream, so as to calculate the duration, don't stop
as soon as all streams have seen at least one packet.
Otherwise the duration will be shorter than it
should be. We must keep reading to the end-of-file.
patch by neilb suse de
author | michael |
---|---|
date | Sat, 18 Aug 2007 00:52:05 +0000 |
parents | fc685315d568 |
children | 153d6efc05b8 |
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 | |
22 #include "nut.h" | |
2350 | 23 #include "tree.h" |
2324 | 24 |
25 static void build_frame_code(AVFormatContext *s){ | |
26 NUTContext *nut = s->priv_data; | |
27 int key_frame, index, pred, stream_id; | |
28 int start=1; | |
29 int end= 254; | |
30 int keyframe_0_esc= s->nb_streams > 2; | |
31 int pred_table[10]; | |
2339
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
32 FrameCode *ft; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
33 |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
34 ft= &nut->frame_code[start]; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
35 ft->flags= FLAG_CODED; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
36 ft->size_mul=1; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
37 ft->pts_delta=1; |
2c8579bcd287
add a universal fallback frame code for the case that no other applies
michael
parents:
2332
diff
changeset
|
38 start++; |
2324 | 39 |
40 if(keyframe_0_esc){ | |
41 /* keyframe = 0 escape */ | |
42 FrameCode *ft= &nut->frame_code[start]; | |
43 ft->flags= FLAG_STREAM_ID | FLAG_SIZE_MSB | FLAG_CODED_PTS; | |
44 ft->size_mul=1; | |
45 start++; | |
46 } | |
47 | |
48 for(stream_id= 0; stream_id<s->nb_streams; stream_id++){ | |
49 int start2= start + (end-start)*stream_id / s->nb_streams; | |
50 int end2 = start + (end-start)*(stream_id+1) / s->nb_streams; | |
51 AVCodecContext *codec = s->streams[stream_id]->codec; | |
52 int is_audio= codec->codec_type == CODEC_TYPE_AUDIO; | |
53 int intra_only= /*codec->intra_only || */is_audio; | |
54 int pred_count; | |
55 | |
56 for(key_frame=0; key_frame<2; key_frame++){ | |
57 if(intra_only && keyframe_0_esc && key_frame==0) | |
58 continue; | |
59 | |
60 { | |
61 FrameCode *ft= &nut->frame_code[start2]; | |
62 ft->flags= FLAG_KEY*key_frame; | |
63 ft->flags|= FLAG_SIZE_MSB | FLAG_CODED_PTS; | |
64 ft->stream_id= stream_id; | |
65 ft->size_mul=1; | |
66 start2++; | |
67 } | |
68 } | |
69 | |
70 key_frame= intra_only; | |
71 #if 1 | |
72 if(is_audio){ | |
73 int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate); | |
74 int pts; | |
75 for(pts=0; pts<2; pts++){ | |
76 for(pred=0; pred<2; pred++){ | |
77 FrameCode *ft= &nut->frame_code[start2]; | |
78 ft->flags= FLAG_KEY*key_frame; | |
79 ft->stream_id= stream_id; | |
80 ft->size_mul=frame_bytes + 2; | |
81 ft->size_lsb=frame_bytes + pred; | |
82 ft->pts_delta=pts; | |
83 start2++; | |
84 } | |
85 } | |
86 }else{ | |
87 FrameCode *ft= &nut->frame_code[start2]; | |
88 ft->flags= FLAG_KEY | FLAG_SIZE_MSB; | |
89 ft->stream_id= stream_id; | |
90 ft->size_mul=1; | |
91 ft->pts_delta=1; | |
92 start2++; | |
93 } | |
94 #endif | |
95 | |
96 if(codec->has_b_frames){ | |
97 pred_count=5; | |
98 pred_table[0]=-2; | |
99 pred_table[1]=-1; | |
100 pred_table[2]=1; | |
101 pred_table[3]=3; | |
102 pred_table[4]=4; | |
103 }else if(codec->codec_id == CODEC_ID_VORBIS){ | |
104 pred_count=3; | |
105 pred_table[0]=2; | |
106 pred_table[1]=9; | |
107 pred_table[2]=16; | |
108 }else{ | |
109 pred_count=1; | |
110 pred_table[0]=1; | |
111 } | |
112 | |
113 for(pred=0; pred<pred_count; pred++){ | |
114 int start3= start2 + (end2-start2)*pred / pred_count; | |
115 int end3 = start2 + (end2-start2)*(pred+1) / pred_count; | |
116 | |
117 for(index=start3; index<end3; index++){ | |
118 FrameCode *ft= &nut->frame_code[index]; | |
119 ft->flags= FLAG_KEY*key_frame; | |
120 ft->flags|= FLAG_SIZE_MSB; | |
121 ft->stream_id= stream_id; | |
122 //FIXME use single byte size and pred from last | |
123 ft->size_mul= end3-start3; | |
124 ft->size_lsb= index - start3; | |
125 ft->pts_delta= pred_table[pred]; | |
126 } | |
127 } | |
128 } | |
129 memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N')); | |
130 nut->frame_code[ 0].flags= | |
131 nut->frame_code[255].flags= | |
132 nut->frame_code['N'].flags= FLAG_INVALID; | |
133 } | |
134 | |
135 /** | |
136 * Gets the length in bytes which is needed to store val as v. | |
137 */ | |
138 static int get_length(uint64_t val){ | |
139 int i=1; | |
140 | |
141 while(val>>=7) | |
142 i++; | |
143 | |
144 return i; | |
145 } | |
146 | |
147 static void put_v(ByteIOContext *bc, uint64_t val){ | |
148 int i= get_length(val); | |
149 | |
150 while(--i>0) | |
151 put_byte(bc, 128 | (val>>(7*i))); | |
152 | |
153 put_byte(bc, val&127); | |
154 } | |
155 | |
2342 | 156 static void put_t(NUTContext *nut, StreamContext *nus, ByteIOContext *bc, uint64_t val){ |
157 val *= nut->time_base_count; | |
158 val += nus->time_base - nut->time_base; | |
159 put_v(bc, val); | |
160 } | |
161 | |
2324 | 162 /** |
2393 | 163 * Stores a string as vb. |
2324 | 164 */ |
165 static void put_str(ByteIOContext *bc, const char *string){ | |
166 int len= strlen(string); | |
167 | |
168 put_v(bc, len); | |
169 put_buffer(bc, string, len); | |
170 } | |
171 | |
172 static void put_s(ByteIOContext *bc, int64_t val){ | |
173 put_v(bc, 2*FFABS(val) - (val>0)); | |
174 } | |
175 | |
176 #ifdef TRACE | |
177 static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ | |
2344 | 178 av_log(NULL, AV_LOG_DEBUG, "put_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); |
2324 | 179 |
180 put_v(bc, v); | |
181 } | |
182 | |
183 static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){ | |
2344 | 184 av_log(NULL, AV_LOG_DEBUG, "put_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); |
2324 | 185 |
186 put_s(bc, v); | |
187 } | |
188 #define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
189 #define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
190 #endif | |
191 | |
2340 | 192 //FIXME remove calculate_checksum |
2347 | 193 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
|
194 uint8_t *dyn_buf=NULL; |
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
195 int dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf); |
2332 | 196 int forw_ptr= dyn_size + 4*calculate_checksum; |
2324 | 197 |
2332 | 198 if(forw_ptr > 4096) |
2347 | 199 init_checksum(bc, av_crc04C11DB7_update, 0); |
200 put_be64(bc, startcode); | |
2332 | 201 put_v(bc, forw_ptr); |
202 if(forw_ptr > 4096) | |
203 put_le32(bc, get_checksum(bc)); | |
204 | |
2324 | 205 if(calculate_checksum) |
206 init_checksum(bc, av_crc04C11DB7_update, 0); | |
2331
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
207 put_buffer(bc, dyn_buf, dyn_size); |
2324 | 208 if(calculate_checksum) |
2331
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
209 put_le32(bc, get_checksum(bc)); |
2324 | 210 |
2331
4d1a56112d92
use a dynamic ByteIOContext instead of using the lavf buffer
michael
parents:
2330
diff
changeset
|
211 av_free(dyn_buf); |
2324 | 212 } |
213 | |
2329 | 214 static void write_mainheader(NUTContext *nut, ByteIOContext *bc){ |
2324 | 215 int i, j, tmp_pts, tmp_flags, tmp_stream, tmp_mul, tmp_size, tmp_fields; |
216 | |
2360
b2eeaa4df665
muxer should now be spec compliant (though it likely still contains bugs!)
michael
parents:
2359
diff
changeset
|
217 put_v(bc, 3); /* version */ |
2329 | 218 put_v(bc, nut->avf->nb_streams); |
2324 | 219 put_v(bc, MAX_DISTANCE); |
220 put_v(bc, nut->time_base_count); | |
221 | |
222 for(i=0; i<nut->time_base_count; i++){ | |
223 put_v(bc, nut->time_base[i].num); | |
224 put_v(bc, nut->time_base[i].den); | |
225 } | |
226 | |
227 tmp_pts=0; | |
228 tmp_mul=1; | |
229 tmp_stream=0; | |
230 for(i=0; i<256;){ | |
231 tmp_fields=0; | |
232 tmp_size=0; | |
233 // tmp_res=0; | |
234 if(tmp_pts != nut->frame_code[i].pts_delta) tmp_fields=1; | |
235 if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2; | |
236 if(tmp_stream != nut->frame_code[i].stream_id) tmp_fields=3; | |
237 if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4; | |
238 // if(tmp_res != nut->frame_code[i].res ) tmp_fields=5; | |
239 | |
240 tmp_pts = nut->frame_code[i].pts_delta; | |
241 tmp_flags = nut->frame_code[i].flags; | |
242 tmp_stream= nut->frame_code[i].stream_id; | |
243 tmp_mul = nut->frame_code[i].size_mul; | |
244 tmp_size = nut->frame_code[i].size_lsb; | |
245 // tmp_res = nut->frame_code[i].res; | |
246 | |
247 for(j=0; i<256; j++,i++){ | |
248 if(i == 'N'){ | |
249 j--; | |
250 continue; | |
251 } | |
252 if(nut->frame_code[i].pts_delta != tmp_pts ) break; | |
253 if(nut->frame_code[i].flags != tmp_flags ) break; | |
254 if(nut->frame_code[i].stream_id != tmp_stream) break; | |
255 if(nut->frame_code[i].size_mul != tmp_mul ) break; | |
256 if(nut->frame_code[i].size_lsb != tmp_size+j) break; | |
257 // if(nut->frame_code[i].res != tmp_res ) break; | |
258 } | |
259 if(j != tmp_mul - tmp_size) tmp_fields=6; | |
260 | |
261 put_v(bc, tmp_flags); | |
262 put_v(bc, tmp_fields); | |
263 if(tmp_fields>0) put_s(bc, tmp_pts); | |
264 if(tmp_fields>1) put_v(bc, tmp_mul); | |
265 if(tmp_fields>2) put_v(bc, tmp_stream); | |
266 if(tmp_fields>3) put_v(bc, tmp_size); | |
267 if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/); | |
268 if(tmp_fields>5) put_v(bc, j); | |
269 } | |
2329 | 270 } |
2324 | 271 |
2330 | 272 static int write_streamheader(NUTContext *nut, ByteIOContext *bc, AVCodecContext *codec, int i){ |
273 put_v(bc, i); | |
274 switch(codec->codec_type){ | |
275 case CODEC_TYPE_VIDEO: put_v(bc, 0); break; | |
276 case CODEC_TYPE_AUDIO: put_v(bc, 1); break; | |
277 // case CODEC_TYPE_TEXT : put_v(bc, 2); break; | |
278 default : put_v(bc, 3); break; | |
279 } | |
280 put_v(bc, 4); | |
281 if (codec->codec_tag){ | |
282 put_le32(bc, codec->codec_tag); | |
283 }else | |
284 return -1; | |
285 | |
2341 | 286 put_v(bc, nut->stream[i].time_base - nut->time_base); |
2330 | 287 put_v(bc, nut->stream[i].msb_pts_shift); |
288 put_v(bc, nut->stream[i].max_pts_distance); | |
289 put_v(bc, codec->has_b_frames); | |
290 put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ | |
291 | |
292 put_v(bc, codec->extradata_size); | |
293 put_buffer(bc, codec->extradata, codec->extradata_size); | |
294 | |
295 switch(codec->codec_type){ | |
296 case CODEC_TYPE_AUDIO: | |
297 put_v(bc, codec->sample_rate); | |
298 put_v(bc, 1); | |
299 put_v(bc, codec->channels); | |
300 break; | |
301 case CODEC_TYPE_VIDEO: | |
302 put_v(bc, codec->width); | |
303 put_v(bc, codec->height); | |
2363 | 304 |
305 if(codec->sample_aspect_ratio.num<=0 || codec->sample_aspect_ratio.den<=0){ | |
306 put_v(bc, 0); | |
307 put_v(bc, 0); | |
308 }else{ | |
309 put_v(bc, codec->sample_aspect_ratio.num); | |
310 put_v(bc, codec->sample_aspect_ratio.den); | |
311 } | |
2330 | 312 put_v(bc, 0); /* csp type -- unknown */ |
313 break; | |
314 default: | |
315 break; | |
316 } | |
317 return 0; | |
318 } | |
319 | |
2358 | 320 static int add_info(ByteIOContext *bc, char *type, char *value){ |
321 put_str(bc, type); | |
322 put_s(bc, -1); | |
323 put_str(bc, value); | |
324 return 1; | |
325 } | |
326 | |
327 static void write_globalinfo(NUTContext *nut, ByteIOContext *bc){ | |
328 AVFormatContext *s= nut->avf; | |
329 ByteIOContext dyn_bc; | |
330 uint8_t *dyn_buf=NULL; | |
331 int count=0, dyn_size; | |
332 | |
333 url_open_dyn_buf(&dyn_bc); | |
334 | |
335 if(s->title [0]) count+= add_info(&dyn_bc, "Title" , s->title); | |
336 if(s->author [0]) count+= add_info(&dyn_bc, "Author" , s->author); | |
337 if(s->copyright[0]) count+= add_info(&dyn_bc, "Copyright", s->copyright); | |
338 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) | |
339 count+= add_info(&dyn_bc, "Encoder" , LIBAVFORMAT_IDENT); | |
340 | |
341 put_v(bc, 0); //stream_if_plus1 | |
342 put_v(bc, 0); //chapter_id | |
343 put_v(bc, 0); //timestamp_start | |
344 put_v(bc, 0); //length | |
345 | |
346 put_v(bc, count); | |
347 | |
348 dyn_size= url_close_dyn_buf(&dyn_bc, &dyn_buf); | |
349 put_buffer(bc, dyn_buf, dyn_size); | |
350 av_free(dyn_buf); | |
351 } | |
352 | |
2345 | 353 static void write_headers(NUTContext *nut, ByteIOContext *bc){ |
354 ByteIOContext dyn_bc; | |
355 int i; | |
356 | |
357 url_open_dyn_buf(&dyn_bc); | |
358 write_mainheader(nut, &dyn_bc); | |
2347 | 359 put_packet(nut, bc, &dyn_bc, 1, MAIN_STARTCODE); |
2345 | 360 |
361 for (i=0; i < nut->avf->nb_streams; i++){ | |
362 AVCodecContext *codec = nut->avf->streams[i]->codec; | |
363 | |
364 url_open_dyn_buf(&dyn_bc); | |
365 write_streamheader(nut, &dyn_bc, codec, i); | |
2347 | 366 put_packet(nut, bc, &dyn_bc, 1, STREAM_STARTCODE); |
2345 | 367 } |
2358 | 368 |
369 url_open_dyn_buf(&dyn_bc); | |
370 write_globalinfo(nut, &dyn_bc); | |
371 put_packet(nut, bc, &dyn_bc, 1, INFO_STARTCODE); | |
2359 | 372 |
373 nut->last_syncpoint_pos= INT_MIN; | |
374 nut->header_count++; | |
2345 | 375 } |
376 | |
2329 | 377 static int write_header(AVFormatContext *s){ |
378 NUTContext *nut = s->priv_data; | |
2345 | 379 ByteIOContext *bc = &s->pb; |
2329 | 380 int i, j; |
381 | |
382 nut->avf= s; | |
383 | |
384 nut->stream = av_mallocz(sizeof(StreamContext)*s->nb_streams); | |
385 nut->time_base= av_mallocz(sizeof(AVRational )*s->nb_streams); | |
386 | |
387 for(i=0; i<s->nb_streams; i++){ | |
388 AVStream *st= s->streams[i]; | |
389 int ssize; | |
390 AVRational time_base; | |
391 ff_parse_specific_params(st->codec, &time_base.den, &ssize, &time_base.num); | |
392 | |
393 av_set_pts_info(st, 64, time_base.num, time_base.den); | |
394 | |
395 for(j=0; j<nut->time_base_count; j++){ | |
396 if(!memcmp(&time_base, &nut->time_base[j], sizeof(AVRational))){ | |
397 break; | |
398 } | |
399 } | |
400 nut->time_base[j]= time_base; | |
401 nut->stream[i].time_base= &nut->time_base[j]; | |
402 if(j==nut->time_base_count) | |
403 nut->time_base_count++; | |
404 | |
405 if(av_q2d(time_base) >= 0.001) | |
406 nut->stream[i].msb_pts_shift = 7; | |
407 else | |
408 nut->stream[i].msb_pts_shift = 14; | |
409 nut->stream[i].max_pts_distance= FFMAX(1/av_q2d(time_base), 1); | |
410 } | |
411 | |
412 build_frame_code(s); | |
413 assert(nut->frame_code['N'].flags == FLAG_INVALID); | |
414 | |
415 put_buffer(bc, ID_STRING, strlen(ID_STRING)); | |
416 put_byte(bc, 0); | |
417 | |
2345 | 418 write_headers(nut, bc); |
2325 | 419 |
2324 | 420 put_flush_packet(bc); |
421 | |
2359 | 422 //FIXME index |
2324 | 423 |
424 return 0; | |
425 } | |
426 | |
2343 | 427 static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc, AVPacket *pkt){ |
428 int flags= 0; | |
429 | |
430 if(pkt->flags & PKT_FLAG_KEY ) flags |= FLAG_KEY; | |
431 if(pkt->stream_index != fc->stream_id ) flags |= FLAG_STREAM_ID; | |
432 if(pkt->size / fc->size_mul ) flags |= FLAG_SIZE_MSB; | |
433 if(pkt->pts - nus->last_pts != fc->pts_delta) flags |= FLAG_CODED_PTS; | |
434 if(pkt->size > 2*nut->max_distance ) flags |= FLAG_CHECKSUM; | |
435 if(FFABS(pkt->pts - nus->last_pts) | |
436 > nus->max_pts_distance) flags |= FLAG_CHECKSUM; | |
437 | |
2371 | 438 return flags | (fc->flags & FLAG_CODED); |
2343 | 439 } |
440 | |
2324 | 441 static int write_packet(AVFormatContext *s, AVPacket *pkt){ |
2343 | 442 NUTContext *nut = s->priv_data; |
443 StreamContext *nus= &nut->stream[pkt->stream_index]; | |
444 ByteIOContext *bc = &s->pb, dyn_bc; | |
445 FrameCode *fc; | |
446 int64_t coded_pts; | |
447 int best_length, frame_code, flags, needed_flags, i; | |
448 int key_frame = !!(pkt->flags & PKT_FLAG_KEY); | |
449 int store_sp=0; | |
450 | |
2359 | 451 if(1LL<<(20+3*nut->header_count) <= url_ftell(bc)) |
452 write_headers(nut, bc); | |
453 | |
2343 | 454 if(key_frame && !!(nus->last_flags & FLAG_KEY)) |
455 store_sp= 1; | |
456 | |
457 if(pkt->size + 30/*FIXME check*/ + url_ftell(bc) >= nut->last_syncpoint_pos + nut->max_distance) | |
458 store_sp= 1; | |
459 | |
2393 | 460 //FIXME: Ensure store_sp is 1 in the first place. |
2343 | 461 |
462 if(store_sp){ | |
2350 | 463 syncpoint_t *sp, dummy= {.pos= INT64_MAX}; |
464 | |
2343 | 465 ff_nut_reset_ts(nut, *nus->time_base, pkt->dts); |
2350 | 466 for(i=0; i<s->nb_streams; i++){ |
467 AVStream *st= s->streams[i]; | |
468 int index= av_index_search_timestamp(st, pkt->dts, AVSEEK_FLAG_BACKWARD); | |
469 if(index<0) dummy.pos=0; | |
470 else dummy.pos= FFMIN(dummy.pos, st->index_entries[index].pos); | |
471 } | |
472 sp= av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, NULL); | |
2343 | 473 |
474 nut->last_syncpoint_pos= url_ftell(bc); | |
475 url_open_dyn_buf(&dyn_bc); | |
476 put_t(nut, nus, &dyn_bc, pkt->dts); | |
2350 | 477 put_v(&dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos)>>4 : 0); |
2347 | 478 put_packet(nut, bc, &dyn_bc, 1, SYNCPOINT_STARTCODE); |
2350 | 479 |
480 ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0/*unused*/, pkt->dts); | |
2343 | 481 } |
482 assert(nus->last_pts != AV_NOPTS_VALUE); | |
483 | |
484 coded_pts = pkt->pts & ((1<<nus->msb_pts_shift)-1); | |
485 if(ff_lsb2full(nus, coded_pts) != pkt->pts) | |
486 coded_pts= pkt->pts + (1<<nus->msb_pts_shift); | |
487 | |
488 best_length=INT_MAX; | |
489 frame_code= -1; | |
490 for(i=0; i<256; i++){ | |
491 int length= 0; | |
492 FrameCode *fc= &nut->frame_code[i]; | |
493 int flags= fc->flags; | |
494 | |
495 if(flags & FLAG_INVALID) | |
496 continue; | |
497 needed_flags= get_needed_flags(nut, nus, fc, pkt); | |
498 | |
499 if(flags & FLAG_CODED){ | |
500 length++; | |
2372 | 501 flags = needed_flags; |
2343 | 502 } |
503 | |
504 if((flags & needed_flags) != needed_flags) | |
505 continue; | |
506 | |
507 if((flags ^ needed_flags) & FLAG_KEY) | |
508 continue; | |
509 | |
510 if(flags & FLAG_STREAM_ID) | |
511 length+= get_length(pkt->stream_index); | |
512 | |
513 if(pkt->size % fc->size_mul != fc->size_lsb) | |
514 continue; | |
515 if(flags & FLAG_SIZE_MSB) | |
516 length += get_length(pkt->size / fc->size_mul); | |
517 | |
518 if(flags & FLAG_CHECKSUM) | |
519 length+=4; | |
520 | |
521 if(flags & FLAG_CODED_PTS) | |
522 length += get_length(coded_pts); | |
523 | |
524 length*=4; | |
525 length+= !(flags & FLAG_CODED_PTS); | |
526 length+= !(flags & FLAG_CHECKSUM); | |
527 | |
528 if(length < best_length){ | |
529 best_length= length; | |
530 frame_code=i; | |
531 } | |
532 } | |
533 assert(frame_code != -1); | |
534 fc= &nut->frame_code[frame_code]; | |
535 flags= fc->flags; | |
536 needed_flags= get_needed_flags(nut, nus, fc, pkt); | |
537 | |
538 init_checksum(bc, av_crc04C11DB7_update, 0); | |
539 put_byte(bc, frame_code); | |
540 if(flags & FLAG_CODED){ | |
541 put_v(bc, (flags^needed_flags) & ~(FLAG_CODED)); | |
542 flags = needed_flags; | |
543 } | |
544 if(flags & FLAG_STREAM_ID) put_v(bc, pkt->stream_index); | |
545 if(flags & FLAG_CODED_PTS) put_v(bc, coded_pts); | |
546 if(flags & FLAG_SIZE_MSB) put_v(bc, pkt->size / fc->size_mul); | |
547 | |
548 if(flags & FLAG_CHECKSUM) put_le32(bc, get_checksum(bc)); | |
549 else get_checksum(bc); | |
550 | |
551 put_buffer(bc, pkt->data, pkt->size); | |
552 nus->last_flags= flags; | |
2350 | 553 |
554 //FIXME just store one per syncpoint | |
555 if(flags & FLAG_KEY) | |
556 av_add_index_entry( | |
557 s->streams[pkt->stream_index], | |
558 nut->last_syncpoint_pos, | |
559 pkt->pts, | |
560 0, | |
561 0, | |
562 AVINDEX_KEYFRAME); | |
563 | |
2324 | 564 return 0; |
565 } | |
566 | |
2346
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
567 static int write_trailer(AVFormatContext *s){ |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
568 NUTContext *nut= s->priv_data; |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
569 ByteIOContext *bc= &s->pb; |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
570 |
2359 | 571 while(nut->header_count<3) |
572 write_headers(nut, bc); | |
2346
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
573 put_flush_packet(bc); |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
574 |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
575 return 0; |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
576 } |
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
577 |
2324 | 578 AVOutputFormat nut_muxer = { |
579 "nut", | |
580 "nut format", | |
581 "video/x-nut", | |
582 "nut", | |
583 sizeof(NUTContext), | |
584 #ifdef CONFIG_LIBVORBIS | |
585 CODEC_ID_VORBIS, | |
586 #elif defined(CONFIG_LIBMP3LAME) | |
587 CODEC_ID_MP3, | |
588 #else | |
589 CODEC_ID_MP2, /* AC3 needs liba52 decoder */ | |
590 #endif | |
591 CODEC_ID_MPEG4, | |
592 write_header, | |
593 write_packet, | |
2346
cbcd840cf971
store headers twice (getting closer to spec compliance ...)
michael
parents:
2345
diff
changeset
|
594 write_trailer, |
2324 | 595 .flags = AVFMT_GLOBALHEADER, |
2325 | 596 .codec_tag= (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0}, |
2324 | 597 }; |