ffmpeg / libavformat / nut.c @ ccb15994
History | View | Annotate | Download (42.5 KB)
1 |
/*
|
---|---|
2 |
* "NUT" Container Format muxer and demuxer (DRAFT-200403??)
|
3 |
* Copyright (c) 2003 Alex Beregszaszi
|
4 |
* Copyright (c) 2004 Michael Niedermayer
|
5 |
*
|
6 |
* This library is free software; you can redistribute it and/or
|
7 |
* modify it under the terms of the GNU Lesser General Public
|
8 |
* License as published by the Free Software Foundation; either
|
9 |
* version 2 of the License, or (at your option) any later version.
|
10 |
*
|
11 |
* This library is distributed in the hope that it will be useful,
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
* Lesser General Public License for more details.
|
15 |
*
|
16 |
* You should have received a copy of the GNU General Public
|
17 |
* License along with this library; if not, write to the Free Software
|
18 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
19 |
*
|
20 |
*
|
21 |
* Visit the official site at http://www.nut.hu/
|
22 |
*
|
23 |
*/
|
24 |
|
25 |
/*
|
26 |
* TODO:
|
27 |
* - index writing
|
28 |
* - index packet reading support
|
29 |
*/
|
30 |
|
31 |
//#define DEBUG 1
|
32 |
|
33 |
#include <limits.h> |
34 |
#include "avformat.h" |
35 |
#include "mpegaudio.h" |
36 |
#include "riff.h" |
37 |
#include "adler32.h" |
38 |
|
39 |
#undef NDEBUG
|
40 |
#include <assert.h> |
41 |
|
42 |
//#define TRACE
|
43 |
|
44 |
//from /dev/random
|
45 |
|
46 |
#define MAIN_STARTCODE (0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48)) |
47 |
#define STREAM_STARTCODE (0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48)) |
48 |
#define KEYFRAME_STARTCODE (0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48)) |
49 |
#define INDEX_STARTCODE (0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48)) |
50 |
#define INFO_STARTCODE (0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48)) |
51 |
|
52 |
#define ID_STRING "nut/multimedia container\0" |
53 |
|
54 |
#define MAX_DISTANCE (1024*16-1) |
55 |
#define MAX_SHORT_DISTANCE (1024*4-1) |
56 |
|
57 |
#define FLAG_DATA_SIZE 1 |
58 |
#define FLAG_KEY_FRAME 2 |
59 |
#define FLAG_INVALID 4 |
60 |
|
61 |
typedef struct { |
62 |
uint8_t flags; |
63 |
uint8_t stream_id_plus1; |
64 |
uint16_t size_mul; |
65 |
uint16_t size_lsb; |
66 |
int16_t timestamp_delta; |
67 |
uint8_t reserved_count; |
68 |
} FrameCode; |
69 |
|
70 |
typedef struct { |
71 |
int last_key_frame;
|
72 |
int msb_timestamp_shift;
|
73 |
int rate_num;
|
74 |
int rate_den;
|
75 |
int64_t last_pts; |
76 |
int64_t last_sync_pos; ///<pos of last 1/2 type frame
|
77 |
int decode_delay;
|
78 |
} StreamContext; |
79 |
|
80 |
typedef struct { |
81 |
AVFormatContext *avf; |
82 |
int written_packet_size;
|
83 |
int64_t packet_start[3]; //0-> startcode less, 1-> short startcode 2-> long startcodes |
84 |
FrameCode frame_code[256];
|
85 |
unsigned int stream_count; |
86 |
uint64_t next_startcode; ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable
|
87 |
StreamContext *stream; |
88 |
int max_distance;
|
89 |
int max_short_distance;
|
90 |
int rate_num;
|
91 |
int rate_den;
|
92 |
int short_startcode;
|
93 |
} NUTContext; |
94 |
|
95 |
static char *info_table[][2]={ |
96 |
{NULL , NULL }, // end |
97 |
{NULL , NULL }, |
98 |
{NULL , "UTF8"}, |
99 |
{NULL , "v"}, |
100 |
{NULL , "s"}, |
101 |
{"StreamId" , "v"}, |
102 |
{"SegmentId" , "v"}, |
103 |
{"StartTimestamp" , "v"}, |
104 |
{"EndTimestamp" , "v"}, |
105 |
{"Author" , "UTF8"}, |
106 |
{"Title" , "UTF8"}, |
107 |
{"Description" , "UTF8"}, |
108 |
{"Copyright" , "UTF8"}, |
109 |
{"Encoder" , "UTF8"}, |
110 |
{"Keyword" , "UTF8"}, |
111 |
{"Cover" , "JPEG"}, |
112 |
{"Cover" , "PNG"}, |
113 |
}; |
114 |
|
115 |
void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale); |
116 |
|
117 |
static void update(NUTContext *nut, int stream_index, int64_t frame_start, int frame_type, int frame_code, int key_frame, int size, int64_t pts){ |
118 |
StreamContext *stream= &nut->stream[stream_index]; |
119 |
|
120 |
stream->last_key_frame= key_frame; |
121 |
nut->packet_start[ frame_type ]= frame_start; |
122 |
stream->last_pts= pts; |
123 |
} |
124 |
|
125 |
static void reset(AVFormatContext *s, int64_t global_ts){ |
126 |
NUTContext *nut = s->priv_data; |
127 |
int i;
|
128 |
|
129 |
for(i=0; i<s->nb_streams; i++){ |
130 |
StreamContext *stream= &nut->stream[i]; |
131 |
|
132 |
stream->last_key_frame= 1;
|
133 |
|
134 |
stream->last_pts= av_rescale(global_ts, stream->rate_num*(int64_t)nut->rate_den, stream->rate_den*(int64_t)nut->rate_num); |
135 |
} |
136 |
} |
137 |
|
138 |
static void build_frame_code(AVFormatContext *s){ |
139 |
NUTContext *nut = s->priv_data; |
140 |
int key_frame, index, pred, stream_id;
|
141 |
int start=0; |
142 |
int end= 255; |
143 |
int keyframe_0_esc= s->nb_streams > 2; |
144 |
int pred_table[10]; |
145 |
|
146 |
if(keyframe_0_esc){
|
147 |
/* keyframe = 0 escape */
|
148 |
FrameCode *ft= &nut->frame_code[start]; |
149 |
ft->flags= FLAG_DATA_SIZE; |
150 |
ft->stream_id_plus1= 0;
|
151 |
ft->size_mul=1;
|
152 |
ft->timestamp_delta=0;
|
153 |
start++; |
154 |
} |
155 |
|
156 |
for(stream_id= 0; stream_id<s->nb_streams; stream_id++){ |
157 |
int start2= start + (end-start)*stream_id / s->nb_streams;
|
158 |
int end2 = start + (end-start)*(stream_id+1) / s->nb_streams; |
159 |
AVCodecContext *codec = s->streams[stream_id]->codec; |
160 |
int is_audio= codec->codec_type == CODEC_TYPE_AUDIO;
|
161 |
int intra_only= /*codec->intra_only || */is_audio; |
162 |
int pred_count;
|
163 |
|
164 |
for(key_frame=0; key_frame<2; key_frame++){ |
165 |
if(intra_only && keyframe_0_esc && key_frame==0) |
166 |
continue;
|
167 |
|
168 |
{ |
169 |
FrameCode *ft= &nut->frame_code[start2]; |
170 |
ft->flags= FLAG_KEY_FRAME*key_frame; |
171 |
ft->flags|= FLAG_DATA_SIZE; |
172 |
ft->stream_id_plus1= stream_id + 1;
|
173 |
ft->size_mul=1;
|
174 |
ft->timestamp_delta=0;
|
175 |
start2++; |
176 |
} |
177 |
} |
178 |
|
179 |
key_frame= intra_only; |
180 |
#if 1 |
181 |
if(is_audio){
|
182 |
int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate); |
183 |
int pts;
|
184 |
for(pts=0; pts<2; pts++){ |
185 |
for(pred=0; pred<2; pred++){ |
186 |
FrameCode *ft= &nut->frame_code[start2]; |
187 |
ft->flags= FLAG_KEY_FRAME*key_frame; |
188 |
ft->stream_id_plus1= stream_id + 1;
|
189 |
ft->size_mul=frame_bytes + 2;
|
190 |
ft->size_lsb=frame_bytes + pred; |
191 |
ft->timestamp_delta=pts; |
192 |
start2++; |
193 |
} |
194 |
} |
195 |
}else{
|
196 |
FrameCode *ft= &nut->frame_code[start2]; |
197 |
ft->flags= FLAG_KEY_FRAME | FLAG_DATA_SIZE; |
198 |
ft->stream_id_plus1= stream_id + 1;
|
199 |
ft->size_mul=1;
|
200 |
ft->timestamp_delta=1;
|
201 |
start2++; |
202 |
} |
203 |
#endif
|
204 |
|
205 |
if(codec->has_b_frames){
|
206 |
pred_count=5;
|
207 |
pred_table[0]=-2; |
208 |
pred_table[1]=-1; |
209 |
pred_table[2]=1; |
210 |
pred_table[3]=3; |
211 |
pred_table[4]=4; |
212 |
}else if(codec->codec_id == CODEC_ID_VORBIS){ |
213 |
pred_count=3;
|
214 |
pred_table[0]=2; |
215 |
pred_table[1]=9; |
216 |
pred_table[2]=16; |
217 |
}else{
|
218 |
pred_count=1;
|
219 |
pred_table[0]=1; |
220 |
} |
221 |
|
222 |
for(pred=0; pred<pred_count; pred++){ |
223 |
int start3= start2 + (end2-start2)*pred / pred_count;
|
224 |
int end3 = start2 + (end2-start2)*(pred+1) / pred_count; |
225 |
|
226 |
for(index=start3; index<end3; index++){
|
227 |
FrameCode *ft= &nut->frame_code[index]; |
228 |
ft->flags= FLAG_KEY_FRAME*key_frame; |
229 |
ft->flags|= FLAG_DATA_SIZE; |
230 |
ft->stream_id_plus1= stream_id + 1;
|
231 |
//FIXME use single byte size and pred from last
|
232 |
ft->size_mul= end3-start3; |
233 |
ft->size_lsb= index - start3; |
234 |
ft->timestamp_delta= pred_table[pred]; |
235 |
} |
236 |
} |
237 |
} |
238 |
memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N')); |
239 |
nut->frame_code['N'].flags= FLAG_INVALID;
|
240 |
} |
241 |
|
242 |
static uint64_t get_v(ByteIOContext *bc)
|
243 |
{ |
244 |
uint64_t val = 0;
|
245 |
|
246 |
for(;;)
|
247 |
{ |
248 |
int tmp = get_byte(bc);
|
249 |
|
250 |
if (tmp&0x80) |
251 |
val= (val<<7) + tmp - 0x80; |
252 |
else{
|
253 |
//av_log(NULL, AV_LOG_DEBUG, "get_v()= %lld\n", (val<<7) + tmp);
|
254 |
return (val<<7) + tmp; |
255 |
} |
256 |
} |
257 |
return -1; |
258 |
} |
259 |
|
260 |
static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ |
261 |
unsigned int len= get_v(bc); |
262 |
|
263 |
if(len && maxlen)
|
264 |
get_buffer(bc, string, FFMIN(len, maxlen)); |
265 |
while(len > maxlen){
|
266 |
get_byte(bc); |
267 |
len--; |
268 |
} |
269 |
|
270 |
if(maxlen)
|
271 |
string[FFMIN(len, maxlen-1)]= 0; |
272 |
|
273 |
if(maxlen == len)
|
274 |
return -1; |
275 |
else
|
276 |
return 0; |
277 |
} |
278 |
|
279 |
static int64_t get_s(ByteIOContext *bc){
|
280 |
int64_t v = get_v(bc) + 1;
|
281 |
|
282 |
if (v&1) return -(v>>1); |
283 |
else return (v>>1); |
284 |
} |
285 |
|
286 |
static uint64_t get_vb(ByteIOContext *bc){
|
287 |
uint64_t val=0;
|
288 |
unsigned int i= get_v(bc); |
289 |
|
290 |
if(i>8) |
291 |
return UINT64_MAX;
|
292 |
|
293 |
while(i--)
|
294 |
val = (val<<8) + get_byte(bc);
|
295 |
|
296 |
//av_log(NULL, AV_LOG_DEBUG, "get_vb()= %lld\n", val);
|
297 |
return val;
|
298 |
} |
299 |
|
300 |
#ifdef TRACE
|
301 |
static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){ |
302 |
uint64_t v= get_v(bc); |
303 |
|
304 |
printf("get_v %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
305 |
return v;
|
306 |
} |
307 |
|
308 |
static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){ |
309 |
int64_t v= get_s(bc); |
310 |
|
311 |
printf("get_s %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
312 |
return v;
|
313 |
} |
314 |
|
315 |
static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){ |
316 |
uint64_t v= get_vb(bc); |
317 |
|
318 |
printf("get_vb %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
319 |
return v;
|
320 |
} |
321 |
#define get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
322 |
#define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
323 |
#define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
324 |
#endif
|
325 |
|
326 |
|
327 |
static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum) |
328 |
{ |
329 |
int64_t start, size; |
330 |
start= url_ftell(bc) - 8;
|
331 |
|
332 |
size= get_v(bc); |
333 |
|
334 |
init_checksum(bc, calculate_checksum ? av_adler32_update : NULL, 1); |
335 |
|
336 |
nut->packet_start[2] = start;
|
337 |
nut->written_packet_size= size; |
338 |
|
339 |
return size;
|
340 |
} |
341 |
|
342 |
static int check_checksum(ByteIOContext *bc){ |
343 |
unsigned long checksum= get_checksum(bc); |
344 |
return checksum != get_be32(bc);
|
345 |
} |
346 |
|
347 |
/**
|
348 |
*
|
349 |
*/
|
350 |
static int get_length(uint64_t val){ |
351 |
int i;
|
352 |
|
353 |
for (i=7; val>>i; i+=7); |
354 |
|
355 |
return i;
|
356 |
} |
357 |
|
358 |
static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){
|
359 |
uint64_t state=0;
|
360 |
|
361 |
if(pos >= 0) |
362 |
url_fseek(bc, pos, SEEK_SET); //note, this may fail if the stream isnt seekable, but that shouldnt matter, as in this case we simply start where we are currently
|
363 |
|
364 |
while(!url_feof(bc)){
|
365 |
state= (state<<8) | get_byte(bc);
|
366 |
if((state>>56) != 'N') |
367 |
continue;
|
368 |
switch(state){
|
369 |
case MAIN_STARTCODE:
|
370 |
case STREAM_STARTCODE:
|
371 |
case KEYFRAME_STARTCODE:
|
372 |
case INFO_STARTCODE:
|
373 |
case INDEX_STARTCODE:
|
374 |
return state;
|
375 |
} |
376 |
} |
377 |
|
378 |
return 0; |
379 |
} |
380 |
|
381 |
/**
|
382 |
* find the given startcode.
|
383 |
* @param code the startcode
|
384 |
* @param pos the start position of the search, or -1 if the current position
|
385 |
* @returns the position of the startcode or -1 if not found
|
386 |
*/
|
387 |
static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){
|
388 |
for(;;){
|
389 |
uint64_t startcode= find_any_startcode(bc, pos); |
390 |
if(startcode == code)
|
391 |
return url_ftell(bc) - 8; |
392 |
else if(startcode == 0) |
393 |
return -1; |
394 |
pos=-1;
|
395 |
} |
396 |
} |
397 |
|
398 |
static int64_t lsb2full(StreamContext *stream, int64_t lsb){
|
399 |
int64_t mask = (1<<stream->msb_timestamp_shift)-1; |
400 |
int64_t delta= stream->last_pts - mask/2;
|
401 |
return ((lsb - delta)&mask) + delta;
|
402 |
} |
403 |
|
404 |
#ifdef CONFIG_MUXERS
|
405 |
|
406 |
static void put_v(ByteIOContext *bc, uint64_t val) |
407 |
{ |
408 |
int i;
|
409 |
|
410 |
//av_log(NULL, AV_LOG_DEBUG, "put_v()= %lld\n", val);
|
411 |
val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently |
412 |
i= get_length(val); |
413 |
|
414 |
for (i-=7; i>0; i-=7){ |
415 |
put_byte(bc, 0x80 | (val>>i));
|
416 |
} |
417 |
|
418 |
put_byte(bc, val&0x7f);
|
419 |
} |
420 |
|
421 |
/**
|
422 |
* stores a string as vb.
|
423 |
*/
|
424 |
static void put_str(ByteIOContext *bc, const char *string){ |
425 |
int len= strlen(string);
|
426 |
|
427 |
put_v(bc, len); |
428 |
put_buffer(bc, string, len); |
429 |
} |
430 |
|
431 |
static void put_s(ByteIOContext *bc, int64_t val){ |
432 |
if (val<=0) put_v(bc, -2*val ); |
433 |
else put_v(bc, 2*val-1); |
434 |
} |
435 |
|
436 |
static void put_vb(ByteIOContext *bc, uint64_t val){ |
437 |
int i;
|
438 |
|
439 |
for (i=8; val>>i; i+=8); |
440 |
|
441 |
put_v(bc, i>>3);
|
442 |
for(i-=8; i>=0; i-=8) |
443 |
put_byte(bc, (val>>i)&0xFF);
|
444 |
} |
445 |
|
446 |
#ifdef TRACE
|
447 |
static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ |
448 |
printf("get_v %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
449 |
|
450 |
put_v(bc, v); |
451 |
} |
452 |
|
453 |
static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){ |
454 |
printf("get_s %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
455 |
|
456 |
put_s(bc, v); |
457 |
} |
458 |
|
459 |
static inline void put_vb_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ |
460 |
printf("get_vb %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
461 |
|
462 |
put_vb(bc, v); |
463 |
} |
464 |
#define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
465 |
#define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
466 |
#define put_vb(bc, v) put_vb_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
467 |
#endif
|
468 |
|
469 |
static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum) |
470 |
{ |
471 |
put_flush_packet(bc); |
472 |
nut->packet_start[2]= url_ftell(bc) - 8; |
473 |
nut->written_packet_size = max_size; |
474 |
|
475 |
/* packet header */
|
476 |
put_v(bc, nut->written_packet_size); /* forward ptr */
|
477 |
|
478 |
if(calculate_checksum)
|
479 |
init_checksum(bc, av_adler32_update, 1);
|
480 |
|
481 |
return 0; |
482 |
} |
483 |
|
484 |
/**
|
485 |
*
|
486 |
* must not be called more then once per packet
|
487 |
*/
|
488 |
static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){ |
489 |
int64_t start= nut->packet_start[2];
|
490 |
int64_t cur= url_ftell(bc); |
491 |
int size= cur - start - get_length(nut->written_packet_size)/7 - 8; |
492 |
|
493 |
if(calculate_checksum)
|
494 |
size += 4;
|
495 |
|
496 |
if(size != nut->written_packet_size){
|
497 |
int i;
|
498 |
|
499 |
assert( size <= nut->written_packet_size ); |
500 |
|
501 |
url_fseek(bc, start + 8, SEEK_SET);
|
502 |
for(i=get_length(size); i < get_length(nut->written_packet_size); i+=7) |
503 |
put_byte(bc, 0x80);
|
504 |
put_v(bc, size); |
505 |
|
506 |
url_fseek(bc, cur, SEEK_SET); |
507 |
nut->written_packet_size= size; //FIXME may fail if multiple updates with differing sizes, as get_length may differ
|
508 |
|
509 |
if(calculate_checksum)
|
510 |
put_be32(bc, get_checksum(bc)); |
511 |
} |
512 |
|
513 |
return 0; |
514 |
} |
515 |
|
516 |
static int nut_write_header(AVFormatContext *s) |
517 |
{ |
518 |
NUTContext *nut = s->priv_data; |
519 |
ByteIOContext *bc = &s->pb; |
520 |
AVCodecContext *codec; |
521 |
int i, j, tmp_time, tmp_flags,tmp_stream, tmp_mul, tmp_size, tmp_fields;
|
522 |
|
523 |
if (strcmp(s->filename, "./data/b-libav.nut")) { |
524 |
av_log(s, AV_LOG_ERROR, " libavformat NUT is non-compliant and disabled\n");
|
525 |
return -1; |
526 |
} |
527 |
|
528 |
nut->avf= s; |
529 |
|
530 |
nut->stream = |
531 |
av_mallocz(sizeof(StreamContext)*s->nb_streams);
|
532 |
|
533 |
|
534 |
put_buffer(bc, ID_STRING, strlen(ID_STRING)); |
535 |
put_byte(bc, 0);
|
536 |
nut->packet_start[2]= url_ftell(bc);
|
537 |
|
538 |
/* main header */
|
539 |
put_be64(bc, MAIN_STARTCODE); |
540 |
put_packetheader(nut, bc, 120+5*256, 1); |
541 |
put_v(bc, 2); /* version */ |
542 |
put_v(bc, s->nb_streams); |
543 |
put_v(bc, MAX_DISTANCE); |
544 |
put_v(bc, MAX_SHORT_DISTANCE); |
545 |
|
546 |
put_v(bc, nut->rate_num=1);
|
547 |
put_v(bc, nut->rate_den=2);
|
548 |
put_v(bc, nut->short_startcode=0x4EFE79);
|
549 |
|
550 |
build_frame_code(s); |
551 |
assert(nut->frame_code['N'].flags == FLAG_INVALID);
|
552 |
|
553 |
tmp_time= tmp_flags= tmp_stream= tmp_mul= tmp_size= /*tmp_res=*/ INT_MAX;
|
554 |
for(i=0; i<256;){ |
555 |
tmp_fields=0;
|
556 |
tmp_size= 0;
|
557 |
if(tmp_time != nut->frame_code[i].timestamp_delta) tmp_fields=1; |
558 |
if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2; |
559 |
if(tmp_stream != nut->frame_code[i].stream_id_plus1) tmp_fields=3; |
560 |
if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4; |
561 |
// if(tmp_res != nut->frame_code[i].res ) tmp_fields=5;
|
562 |
|
563 |
tmp_time = nut->frame_code[i].timestamp_delta; |
564 |
tmp_flags = nut->frame_code[i].flags; |
565 |
tmp_stream= nut->frame_code[i].stream_id_plus1; |
566 |
tmp_mul = nut->frame_code[i].size_mul; |
567 |
tmp_size = nut->frame_code[i].size_lsb; |
568 |
// tmp_res = nut->frame_code[i].res;
|
569 |
|
570 |
for(j=0; i<256; j++,i++){ |
571 |
if(nut->frame_code[i].timestamp_delta != tmp_time ) break; |
572 |
if(nut->frame_code[i].flags != tmp_flags ) break; |
573 |
if(nut->frame_code[i].stream_id_plus1 != tmp_stream) break; |
574 |
if(nut->frame_code[i].size_mul != tmp_mul ) break; |
575 |
if(nut->frame_code[i].size_lsb != tmp_size+j) break; |
576 |
// if(nut->frame_code[i].res != tmp_res ) break;
|
577 |
} |
578 |
if(j != tmp_mul - tmp_size) tmp_fields=6; |
579 |
|
580 |
put_v(bc, tmp_flags); |
581 |
put_v(bc, tmp_fields); |
582 |
if(tmp_fields>0) put_s(bc, tmp_time); |
583 |
if(tmp_fields>1) put_v(bc, tmp_mul); |
584 |
if(tmp_fields>2) put_v(bc, tmp_stream); |
585 |
if(tmp_fields>3) put_v(bc, tmp_size); |
586 |
if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/); |
587 |
if(tmp_fields>5) put_v(bc, j); |
588 |
} |
589 |
|
590 |
update_packetheader(nut, bc, 0, 1); |
591 |
|
592 |
/* stream headers */
|
593 |
for (i = 0; i < s->nb_streams; i++) |
594 |
{ |
595 |
int nom, denom, ssize;
|
596 |
|
597 |
codec = s->streams[i]->codec; |
598 |
|
599 |
put_be64(bc, STREAM_STARTCODE); |
600 |
put_packetheader(nut, bc, 120 + codec->extradata_size, 1); |
601 |
put_v(bc, i /*s->streams[i]->index*/);
|
602 |
switch(codec->codec_type){
|
603 |
case CODEC_TYPE_VIDEO: put_v(bc, 0); break; |
604 |
case CODEC_TYPE_AUDIO: put_v(bc, 1); break; |
605 |
// case CODEC_TYPE_TEXT : put_v(bc, 2); break;
|
606 |
case CODEC_TYPE_DATA : put_v(bc, 3); break; |
607 |
default: return -1; |
608 |
} |
609 |
if (codec->codec_tag)
|
610 |
put_vb(bc, codec->codec_tag); |
611 |
else if (codec->codec_type == CODEC_TYPE_VIDEO) |
612 |
{ |
613 |
put_vb(bc, codec_get_bmp_tag(codec->codec_id)); |
614 |
} |
615 |
else if (codec->codec_type == CODEC_TYPE_AUDIO) |
616 |
{ |
617 |
put_vb(bc, codec_get_wav_tag(codec->codec_id)); |
618 |
} |
619 |
else
|
620 |
put_vb(bc, 0);
|
621 |
|
622 |
ff_parse_specific_params(codec, &nom, &ssize, &denom); |
623 |
|
624 |
nut->stream[i].rate_num= nom; |
625 |
nut->stream[i].rate_den= denom; |
626 |
av_set_pts_info(s->streams[i], 60, denom, nom);
|
627 |
|
628 |
put_v(bc, codec->bit_rate); |
629 |
put_vb(bc, 0); /* no language code */ |
630 |
put_v(bc, nom); |
631 |
put_v(bc, denom); |
632 |
if(nom / denom < 1000) |
633 |
nut->stream[i].msb_timestamp_shift = 7;
|
634 |
else
|
635 |
nut->stream[i].msb_timestamp_shift = 14;
|
636 |
put_v(bc, nut->stream[i].msb_timestamp_shift); |
637 |
put_v(bc, codec->has_b_frames); |
638 |
put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ |
639 |
|
640 |
if(codec->extradata_size){
|
641 |
put_v(bc, 1);
|
642 |
put_v(bc, codec->extradata_size); |
643 |
put_buffer(bc, codec->extradata, codec->extradata_size); |
644 |
} |
645 |
put_v(bc, 0); /* end of codec specific headers */ |
646 |
|
647 |
switch(codec->codec_type)
|
648 |
{ |
649 |
case CODEC_TYPE_AUDIO:
|
650 |
put_v(bc, codec->sample_rate); |
651 |
put_v(bc, 1);
|
652 |
put_v(bc, codec->channels); |
653 |
break;
|
654 |
case CODEC_TYPE_VIDEO:
|
655 |
put_v(bc, codec->width); |
656 |
put_v(bc, codec->height); |
657 |
put_v(bc, codec->sample_aspect_ratio.num); |
658 |
put_v(bc, codec->sample_aspect_ratio.den); |
659 |
put_v(bc, 0); /* csp type -- unknown */ |
660 |
break;
|
661 |
default:
|
662 |
break;
|
663 |
} |
664 |
update_packetheader(nut, bc, 0, 1); |
665 |
} |
666 |
|
667 |
/* info header */
|
668 |
put_be64(bc, INFO_STARTCODE); |
669 |
put_packetheader(nut, bc, 30+strlen(s->author)+strlen(s->title)+
|
670 |
strlen(s->comment)+strlen(s->copyright)+strlen(LIBAVFORMAT_IDENT), 1);
|
671 |
if (s->author[0]) |
672 |
{ |
673 |
put_v(bc, 9); /* type */ |
674 |
put_str(bc, s->author); |
675 |
} |
676 |
if (s->title[0]) |
677 |
{ |
678 |
put_v(bc, 10); /* type */ |
679 |
put_str(bc, s->title); |
680 |
} |
681 |
if (s->comment[0]) |
682 |
{ |
683 |
put_v(bc, 11); /* type */ |
684 |
put_str(bc, s->comment); |
685 |
} |
686 |
if (s->copyright[0]) |
687 |
{ |
688 |
put_v(bc, 12); /* type */ |
689 |
put_str(bc, s->copyright); |
690 |
} |
691 |
/* encoder */
|
692 |
if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)){ |
693 |
put_v(bc, 13); /* type */ |
694 |
put_str(bc, LIBAVFORMAT_IDENT); |
695 |
} |
696 |
|
697 |
put_v(bc, 0); /* eof info */ |
698 |
update_packetheader(nut, bc, 0, 1); |
699 |
|
700 |
put_flush_packet(bc); |
701 |
|
702 |
return 0; |
703 |
} |
704 |
|
705 |
static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) |
706 |
{ |
707 |
NUTContext *nut = s->priv_data; |
708 |
StreamContext *stream= &nut->stream[pkt->stream_index]; |
709 |
ByteIOContext *bc = &s->pb; |
710 |
int key_frame = 0, full_pts=0; |
711 |
AVCodecContext *enc; |
712 |
int64_t coded_pts; |
713 |
int frame_type, best_length, frame_code, flags, i, size_mul, size_lsb, time_delta;
|
714 |
const int64_t frame_start= url_ftell(bc);
|
715 |
int64_t pts= pkt->pts; |
716 |
int size= pkt->size;
|
717 |
int stream_index= pkt->stream_index;
|
718 |
|
719 |
enc = s->streams[stream_index]->codec; |
720 |
key_frame = !!(pkt->flags & PKT_FLAG_KEY); |
721 |
|
722 |
frame_type=0;
|
723 |
if(frame_start + size + 20 - FFMAX(nut->packet_start[1], nut->packet_start[2]) > MAX_DISTANCE) |
724 |
frame_type=2;
|
725 |
if(key_frame && !stream->last_key_frame)
|
726 |
frame_type=2;
|
727 |
|
728 |
if(frame_type>1){ |
729 |
int64_t global_ts= av_rescale(pts, stream->rate_den*(int64_t)nut->rate_num, stream->rate_num*(int64_t)nut->rate_den); |
730 |
reset(s, global_ts); |
731 |
put_be64(bc, KEYFRAME_STARTCODE); |
732 |
put_v(bc, global_ts); |
733 |
} |
734 |
assert(stream->last_pts != AV_NOPTS_VALUE); |
735 |
coded_pts = pts & ((1<<stream->msb_timestamp_shift)-1); |
736 |
if(lsb2full(stream, coded_pts) != pts)
|
737 |
full_pts=1;
|
738 |
|
739 |
if(full_pts)
|
740 |
coded_pts= pts + (1<<stream->msb_timestamp_shift);
|
741 |
|
742 |
best_length=INT_MAX; |
743 |
frame_code= -1;
|
744 |
for(i=0; i<256; i++){ |
745 |
int stream_id_plus1= nut->frame_code[i].stream_id_plus1;
|
746 |
int fc_key_frame;
|
747 |
int length=0; |
748 |
size_mul= nut->frame_code[i].size_mul; |
749 |
size_lsb= nut->frame_code[i].size_lsb; |
750 |
time_delta= nut->frame_code[i].timestamp_delta; |
751 |
flags= nut->frame_code[i].flags; |
752 |
|
753 |
assert(size_mul > size_lsb); |
754 |
|
755 |
if(stream_id_plus1 == 0) length+= get_length(stream_index); |
756 |
else if(stream_id_plus1 - 1 != stream_index) |
757 |
continue;
|
758 |
fc_key_frame= !!(flags & FLAG_KEY_FRAME); |
759 |
|
760 |
assert(key_frame==0 || key_frame==1); |
761 |
if(fc_key_frame != key_frame)
|
762 |
continue;
|
763 |
|
764 |
if(flags & FLAG_DATA_SIZE){
|
765 |
if(size % size_mul != size_lsb)
|
766 |
continue;
|
767 |
length += get_length(size / size_mul); |
768 |
}else if(size != size_lsb) |
769 |
continue;
|
770 |
|
771 |
if(full_pts && time_delta)
|
772 |
continue;
|
773 |
|
774 |
if(!time_delta){
|
775 |
length += get_length(coded_pts); |
776 |
}else{
|
777 |
if(time_delta != pts - stream->last_pts)
|
778 |
continue;
|
779 |
} |
780 |
|
781 |
if(length < best_length){
|
782 |
best_length= length; |
783 |
frame_code=i; |
784 |
} |
785 |
// av_log(s, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d %d %d\n", key_frame, frame_type, full_pts, size, stream_index, flags, size_mul, size_lsb, stream_id_plus1, length);
|
786 |
} |
787 |
|
788 |
assert(frame_code != -1);
|
789 |
flags= nut->frame_code[frame_code].flags; |
790 |
size_mul= nut->frame_code[frame_code].size_mul; |
791 |
size_lsb= nut->frame_code[frame_code].size_lsb; |
792 |
time_delta= nut->frame_code[frame_code].timestamp_delta; |
793 |
#ifdef TRACE
|
794 |
best_length /= 7;
|
795 |
best_length ++; //frame_code
|
796 |
if(frame_type==2){ |
797 |
best_length += 8; // startcode |
798 |
} |
799 |
av_log(s, AV_LOG_DEBUG, "kf:%d ft:%d pt:%d fc:%2X len:%2d size:%d stream:%d flag:%d mul:%d lsb:%d s+1:%d pts_delta:%d pts:%lld fs:%lld\n", key_frame, frame_type, full_pts ? 1 : 0, frame_code, best_length, size, stream_index, flags, size_mul, size_lsb, nut->frame_code[frame_code].stream_id_plus1,(int)(pts - stream->last_pts), pts, frame_start); |
800 |
// av_log(s, AV_LOG_DEBUG, "%d %d %d\n", stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
|
801 |
#endif
|
802 |
|
803 |
assert(frame_type != 1); //short startcode not implemented yet |
804 |
put_byte(bc, frame_code); |
805 |
|
806 |
if(nut->frame_code[frame_code].stream_id_plus1 == 0) |
807 |
put_v(bc, stream_index); |
808 |
if (!time_delta){
|
809 |
put_v(bc, coded_pts); |
810 |
} |
811 |
if(flags & FLAG_DATA_SIZE)
|
812 |
put_v(bc, size / size_mul); |
813 |
else
|
814 |
assert(size == size_lsb); |
815 |
if(size > MAX_DISTANCE){
|
816 |
assert(frame_type > 1);
|
817 |
} |
818 |
|
819 |
put_buffer(bc, pkt->data, size); |
820 |
|
821 |
update(nut, stream_index, frame_start, frame_type, frame_code, key_frame, size, pts); |
822 |
|
823 |
return 0; |
824 |
} |
825 |
|
826 |
static int nut_write_trailer(AVFormatContext *s) |
827 |
{ |
828 |
NUTContext *nut = s->priv_data; |
829 |
ByteIOContext *bc = &s->pb; |
830 |
|
831 |
#if 0
|
832 |
int i;
|
833 |
|
834 |
/* WRITE INDEX */
|
835 |
|
836 |
for (i = 0; s->nb_streams; i++)
|
837 |
{
|
838 |
put_be64(bc, INDEX_STARTCODE);
|
839 |
put_packetheader(nut, bc, 64, 1);
|
840 |
put_v(bc, s->streams[i]->id);
|
841 |
put_v(bc, ...);
|
842 |
update_packetheader(nut, bc, 0, 1);
|
843 |
}
|
844 |
#endif
|
845 |
|
846 |
put_flush_packet(bc); |
847 |
|
848 |
av_freep(&nut->stream); |
849 |
|
850 |
return 0; |
851 |
} |
852 |
#endif //CONFIG_MUXERS |
853 |
|
854 |
static int nut_probe(AVProbeData *p) |
855 |
{ |
856 |
int i;
|
857 |
uint64_t code= 0xff;
|
858 |
|
859 |
for (i = 0; i < p->buf_size; i++) { |
860 |
code = (code << 8) | p->buf[i];
|
861 |
if (code == MAIN_STARTCODE)
|
862 |
return AVPROBE_SCORE_MAX;
|
863 |
} |
864 |
return 0; |
865 |
} |
866 |
|
867 |
static int decode_main_header(NUTContext *nut){ |
868 |
AVFormatContext *s= nut->avf; |
869 |
ByteIOContext *bc = &s->pb; |
870 |
uint64_t tmp; |
871 |
int i, j, tmp_stream, tmp_mul, tmp_time, tmp_size, count, tmp_res;
|
872 |
|
873 |
get_packetheader(nut, bc, 1);
|
874 |
|
875 |
tmp = get_v(bc); |
876 |
if (tmp != 2){ |
877 |
av_log(s, AV_LOG_ERROR, "bad version (%"PRId64")\n", tmp); |
878 |
return -1; |
879 |
} |
880 |
|
881 |
nut->stream_count = get_v(bc); |
882 |
if(nut->stream_count > MAX_STREAMS){
|
883 |
av_log(s, AV_LOG_ERROR, "too many streams\n");
|
884 |
return -1; |
885 |
} |
886 |
nut->max_distance = get_v(bc); |
887 |
nut->max_short_distance = get_v(bc); |
888 |
nut->rate_num= get_v(bc); |
889 |
nut->rate_den= get_v(bc); |
890 |
nut->short_startcode= get_v(bc); |
891 |
if(nut->short_startcode>>16 != 'N'){ |
892 |
av_log(s, AV_LOG_ERROR, "invalid short startcode %X\n", nut->short_startcode);
|
893 |
return -1; |
894 |
} |
895 |
|
896 |
for(i=0; i<256;){ |
897 |
int tmp_flags = get_v(bc);
|
898 |
int tmp_fields= get_v(bc);
|
899 |
if(tmp_fields>0) tmp_time = get_s(bc); |
900 |
if(tmp_fields>1) tmp_mul = get_v(bc); |
901 |
if(tmp_fields>2) tmp_stream= get_v(bc); |
902 |
if(tmp_fields>3) tmp_size = get_v(bc); |
903 |
else tmp_size = 0; |
904 |
if(tmp_fields>4) tmp_res = get_v(bc); |
905 |
else tmp_res = 0; |
906 |
if(tmp_fields>5) count = get_v(bc); |
907 |
else count = tmp_mul - tmp_size;
|
908 |
|
909 |
while(tmp_fields-- > 6) |
910 |
get_v(bc); |
911 |
|
912 |
if(count == 0 || i+count > 256){ |
913 |
av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i);
|
914 |
return -1; |
915 |
} |
916 |
if(tmp_stream > nut->stream_count + 1){ |
917 |
av_log(s, AV_LOG_ERROR, "illegal stream number\n");
|
918 |
return -1; |
919 |
} |
920 |
|
921 |
for(j=0; j<count; j++,i++){ |
922 |
nut->frame_code[i].flags = tmp_flags ; |
923 |
nut->frame_code[i].timestamp_delta = tmp_time ; |
924 |
nut->frame_code[i].stream_id_plus1 = tmp_stream; |
925 |
nut->frame_code[i].size_mul = tmp_mul ; |
926 |
nut->frame_code[i].size_lsb = tmp_size+j; |
927 |
nut->frame_code[i].reserved_count = tmp_res ; |
928 |
} |
929 |
} |
930 |
if(nut->frame_code['N'].flags != FLAG_INVALID){ |
931 |
av_log(s, AV_LOG_ERROR, "illegal frame_code table\n");
|
932 |
return -1; |
933 |
} |
934 |
|
935 |
if(check_checksum(bc)){
|
936 |
av_log(s, AV_LOG_ERROR, "Main header checksum mismatch\n");
|
937 |
return -1; |
938 |
} |
939 |
|
940 |
return 0; |
941 |
} |
942 |
|
943 |
static int decode_stream_header(NUTContext *nut){ |
944 |
AVFormatContext *s= nut->avf; |
945 |
ByteIOContext *bc = &s->pb; |
946 |
int class, nom, denom, stream_id;
|
947 |
uint64_t tmp; |
948 |
AVStream *st; |
949 |
|
950 |
get_packetheader(nut, bc, 1);
|
951 |
stream_id= get_v(bc); |
952 |
if(stream_id >= nut->stream_count || s->streams[stream_id])
|
953 |
return -1; |
954 |
|
955 |
st = av_new_stream(s, stream_id); |
956 |
if (!st)
|
957 |
return AVERROR_NOMEM;
|
958 |
|
959 |
class = get_v(bc); |
960 |
tmp = get_vb(bc); |
961 |
st->codec->codec_tag= tmp; |
962 |
switch(class)
|
963 |
{ |
964 |
case 0: |
965 |
st->codec->codec_type = CODEC_TYPE_VIDEO; |
966 |
st->codec->codec_id = codec_get_bmp_id(tmp); |
967 |
if (st->codec->codec_id == CODEC_ID_NONE)
|
968 |
av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
|
969 |
break;
|
970 |
case 1: |
971 |
case 32: //compatibility |
972 |
st->codec->codec_type = CODEC_TYPE_AUDIO; |
973 |
st->codec->codec_id = codec_get_wav_id(tmp); |
974 |
if (st->codec->codec_id == CODEC_ID_NONE)
|
975 |
av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
|
976 |
break;
|
977 |
case 2: |
978 |
// st->codec->codec_type = CODEC_TYPE_TEXT;
|
979 |
// break;
|
980 |
case 3: |
981 |
st->codec->codec_type = CODEC_TYPE_DATA; |
982 |
break;
|
983 |
default:
|
984 |
av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class);
|
985 |
return -1; |
986 |
} |
987 |
s->bit_rate += get_v(bc); |
988 |
get_vb(bc); /* language code */
|
989 |
nom = get_v(bc); |
990 |
denom = get_v(bc); |
991 |
nut->stream[stream_id].msb_timestamp_shift = get_v(bc); |
992 |
st->codec->has_b_frames= |
993 |
nut->stream[stream_id].decode_delay= get_v(bc); |
994 |
get_byte(bc); /* flags */
|
995 |
|
996 |
/* codec specific data headers */
|
997 |
while(get_v(bc) != 0){ |
998 |
st->codec->extradata_size= get_v(bc); |
999 |
if((unsigned)st->codec->extradata_size > (1<<30)) |
1000 |
return -1; |
1001 |
st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); |
1002 |
get_buffer(bc, st->codec->extradata, st->codec->extradata_size); |
1003 |
// url_fskip(bc, get_v(bc));
|
1004 |
} |
1005 |
|
1006 |
if (st->codec->codec_type == CODEC_TYPE_VIDEO) /* VIDEO */ |
1007 |
{ |
1008 |
st->codec->width = get_v(bc); |
1009 |
st->codec->height = get_v(bc); |
1010 |
st->codec->sample_aspect_ratio.num= get_v(bc); |
1011 |
st->codec->sample_aspect_ratio.den= get_v(bc); |
1012 |
get_v(bc); /* csp type */
|
1013 |
} |
1014 |
if (st->codec->codec_type == CODEC_TYPE_AUDIO) /* AUDIO */ |
1015 |
{ |
1016 |
st->codec->sample_rate = get_v(bc); |
1017 |
get_v(bc); // samplerate_den
|
1018 |
st->codec->channels = get_v(bc); |
1019 |
} |
1020 |
if(check_checksum(bc)){
|
1021 |
av_log(s, AV_LOG_ERROR, "Stream header %d checksum mismatch\n", stream_id);
|
1022 |
return -1; |
1023 |
} |
1024 |
av_set_pts_info(s->streams[stream_id], 60, denom, nom);
|
1025 |
nut->stream[stream_id].rate_num= nom; |
1026 |
nut->stream[stream_id].rate_den= denom; |
1027 |
return 0; |
1028 |
} |
1029 |
|
1030 |
static int decode_info_header(NUTContext *nut){ |
1031 |
AVFormatContext *s= nut->avf; |
1032 |
ByteIOContext *bc = &s->pb; |
1033 |
|
1034 |
get_packetheader(nut, bc, 1);
|
1035 |
|
1036 |
for(;;){
|
1037 |
int id= get_v(bc);
|
1038 |
char *name, *type, custom_name[256], custom_type[256]; |
1039 |
|
1040 |
if(!id)
|
1041 |
break;
|
1042 |
else if(id >= sizeof(info_table)/sizeof(info_table[0])){ |
1043 |
av_log(s, AV_LOG_ERROR, "info id is too large %d %zd\n", id, sizeof(info_table)/sizeof(info_table[0])); |
1044 |
return -1; |
1045 |
} |
1046 |
|
1047 |
type= info_table[id][1];
|
1048 |
name= info_table[id][0];
|
1049 |
//av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name);
|
1050 |
|
1051 |
if(!type){
|
1052 |
get_str(bc, custom_type, sizeof(custom_type));
|
1053 |
type= custom_type; |
1054 |
} |
1055 |
if(!name){
|
1056 |
get_str(bc, custom_name, sizeof(custom_name));
|
1057 |
name= custom_name; |
1058 |
} |
1059 |
|
1060 |
if(!strcmp(type, "v")){ |
1061 |
get_v(bc); |
1062 |
}else{
|
1063 |
if(!strcmp(name, "Author")) |
1064 |
get_str(bc, s->author, sizeof(s->author));
|
1065 |
else if(!strcmp(name, "Title")) |
1066 |
get_str(bc, s->title, sizeof(s->title));
|
1067 |
else if(!strcmp(name, "Copyright")) |
1068 |
get_str(bc, s->copyright, sizeof(s->copyright));
|
1069 |
else if(!strcmp(name, "Description")) |
1070 |
get_str(bc, s->comment, sizeof(s->comment));
|
1071 |
else
|
1072 |
get_str(bc, NULL, 0); |
1073 |
} |
1074 |
} |
1075 |
if(check_checksum(bc)){
|
1076 |
av_log(s, AV_LOG_ERROR, "Info header checksum mismatch\n");
|
1077 |
return -1; |
1078 |
} |
1079 |
return 0; |
1080 |
} |
1081 |
|
1082 |
static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) |
1083 |
{ |
1084 |
NUTContext *nut = s->priv_data; |
1085 |
ByteIOContext *bc = &s->pb; |
1086 |
int64_t pos; |
1087 |
int inited_stream_count;
|
1088 |
|
1089 |
nut->avf= s; |
1090 |
|
1091 |
/* main header */
|
1092 |
pos=0;
|
1093 |
for(;;){
|
1094 |
pos= find_startcode(bc, MAIN_STARTCODE, pos)+1;
|
1095 |
if (pos<0){ |
1096 |
av_log(s, AV_LOG_ERROR, "no main startcode found\n");
|
1097 |
return -1; |
1098 |
} |
1099 |
if(decode_main_header(nut) >= 0) |
1100 |
break;
|
1101 |
} |
1102 |
|
1103 |
|
1104 |
s->bit_rate = 0;
|
1105 |
|
1106 |
nut->stream = av_malloc(sizeof(StreamContext)*nut->stream_count);
|
1107 |
|
1108 |
/* stream headers */
|
1109 |
pos=0;
|
1110 |
for(inited_stream_count=0; inited_stream_count < nut->stream_count;){ |
1111 |
pos= find_startcode(bc, STREAM_STARTCODE, pos)+1;
|
1112 |
if (pos<0+1){ |
1113 |
av_log(s, AV_LOG_ERROR, "not all stream headers found\n");
|
1114 |
return -1; |
1115 |
} |
1116 |
if(decode_stream_header(nut) >= 0) |
1117 |
inited_stream_count++; |
1118 |
} |
1119 |
|
1120 |
/* info headers */
|
1121 |
pos=0;
|
1122 |
for(;;){
|
1123 |
uint64_t startcode= find_any_startcode(bc, pos); |
1124 |
pos= url_ftell(bc); |
1125 |
|
1126 |
if(startcode==0){ |
1127 |
av_log(s, AV_LOG_ERROR, "EOF before video frames\n");
|
1128 |
return -1; |
1129 |
}else if(startcode == KEYFRAME_STARTCODE){ |
1130 |
nut->next_startcode= startcode; |
1131 |
break;
|
1132 |
}else if(startcode != INFO_STARTCODE){ |
1133 |
continue;
|
1134 |
} |
1135 |
|
1136 |
decode_info_header(nut); |
1137 |
} |
1138 |
|
1139 |
return 0; |
1140 |
} |
1141 |
|
1142 |
static int decode_frame_header(NUTContext *nut, int *key_frame_ret, int64_t *pts_ret, int *stream_id_ret, int frame_code, int frame_type, int64_t frame_start){ |
1143 |
AVFormatContext *s= nut->avf; |
1144 |
StreamContext *stream; |
1145 |
ByteIOContext *bc = &s->pb; |
1146 |
int size, flags, size_mul, size_lsb, stream_id, time_delta;
|
1147 |
int64_t pts = 0;
|
1148 |
|
1149 |
if(frame_type < 2 && frame_start - nut->packet_start[2] > nut->max_distance){ |
1150 |
av_log(s, AV_LOG_ERROR, "last frame must have been damaged\n");
|
1151 |
return -1; |
1152 |
} |
1153 |
|
1154 |
if(frame_type)
|
1155 |
nut->packet_start[ frame_type ]= frame_start; //otherwise 1 goto 1 may happen
|
1156 |
|
1157 |
flags= nut->frame_code[frame_code].flags; |
1158 |
size_mul= nut->frame_code[frame_code].size_mul; |
1159 |
size_lsb= nut->frame_code[frame_code].size_lsb; |
1160 |
stream_id= nut->frame_code[frame_code].stream_id_plus1 - 1;
|
1161 |
time_delta= nut->frame_code[frame_code].timestamp_delta; |
1162 |
|
1163 |
if(stream_id==-1) |
1164 |
stream_id= get_v(bc); |
1165 |
if(stream_id >= s->nb_streams){
|
1166 |
av_log(s, AV_LOG_ERROR, "illegal stream_id\n");
|
1167 |
return -1; |
1168 |
} |
1169 |
stream= &nut->stream[stream_id]; |
1170 |
|
1171 |
// av_log(s, AV_LOG_DEBUG, "ft:%d ppts:%d %d %d\n", frame_type, stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
|
1172 |
|
1173 |
*key_frame_ret= !!(flags & FLAG_KEY_FRAME); |
1174 |
|
1175 |
if(!time_delta){
|
1176 |
int64_t mask = (1<<stream->msb_timestamp_shift)-1; |
1177 |
pts= get_v(bc); |
1178 |
if(pts > mask){
|
1179 |
pts -= mask+1;
|
1180 |
}else{
|
1181 |
if(stream->last_pts == AV_NOPTS_VALUE){
|
1182 |
av_log(s, AV_LOG_ERROR, "no reference pts available\n");
|
1183 |
return -1; |
1184 |
} |
1185 |
pts= lsb2full(stream, pts); |
1186 |
} |
1187 |
}else{
|
1188 |
if(stream->last_pts == AV_NOPTS_VALUE){
|
1189 |
av_log(s, AV_LOG_ERROR, "no reference pts available\n");
|
1190 |
return -1; |
1191 |
} |
1192 |
pts= stream->last_pts + time_delta; |
1193 |
} |
1194 |
|
1195 |
if(*key_frame_ret){
|
1196 |
// av_log(s, AV_LOG_DEBUG, "stream:%d start:%lld pts:%lld length:%lld\n",stream_id, frame_start, av_pts, frame_start - nut->stream[stream_id].last_sync_pos);
|
1197 |
av_add_index_entry( |
1198 |
s->streams[stream_id], |
1199 |
frame_start, |
1200 |
pts, |
1201 |
0,
|
1202 |
frame_start - nut->stream[stream_id].last_sync_pos, |
1203 |
AVINDEX_KEYFRAME); |
1204 |
nut->stream[stream_id].last_sync_pos= frame_start; |
1205 |
// assert(nut->packet_start == frame_start);
|
1206 |
} |
1207 |
|
1208 |
assert(size_mul > size_lsb); |
1209 |
size= size_lsb; |
1210 |
if(flags & FLAG_DATA_SIZE)
|
1211 |
size+= size_mul*get_v(bc); |
1212 |
|
1213 |
#ifdef TRACE
|
1214 |
av_log(s, AV_LOG_DEBUG, "fs:%lld fc:%d ft:%d kf:%d pts:%lld size:%d mul:%d lsb:%d flags:%d delta:%d\n", frame_start, frame_code, frame_type, *key_frame_ret, pts, size, size_mul, size_lsb, flags, time_delta);
|
1215 |
#endif
|
1216 |
|
1217 |
if(frame_type==0 && url_ftell(bc) - nut->packet_start[2] + size > nut->max_distance){ |
1218 |
av_log(s, AV_LOG_ERROR, "frame size too large\n");
|
1219 |
return -1; |
1220 |
} |
1221 |
|
1222 |
*stream_id_ret = stream_id; |
1223 |
*pts_ret = pts; |
1224 |
|
1225 |
update(nut, stream_id, frame_start, frame_type, frame_code, *key_frame_ret, size, pts); |
1226 |
|
1227 |
return size;
|
1228 |
} |
1229 |
|
1230 |
static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type, int64_t frame_start){ |
1231 |
AVFormatContext *s= nut->avf; |
1232 |
ByteIOContext *bc = &s->pb; |
1233 |
int size, stream_id, key_frame, discard;
|
1234 |
int64_t pts, last_IP_pts; |
1235 |
|
1236 |
size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, frame_start); |
1237 |
if(size < 0) |
1238 |
return -1; |
1239 |
|
1240 |
discard= s->streams[ stream_id ]->discard; |
1241 |
last_IP_pts= s->streams[ stream_id ]->last_IP_pts; |
1242 |
if( (discard >= AVDISCARD_NONKEY && !key_frame)
|
1243 |
||(discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE && last_IP_pts > pts) |
1244 |
|| discard >= AVDISCARD_ALL){ |
1245 |
url_fskip(bc, size); |
1246 |
return 1; |
1247 |
} |
1248 |
|
1249 |
av_get_packet(bc, pkt, size); |
1250 |
pkt->stream_index = stream_id; |
1251 |
if (key_frame)
|
1252 |
pkt->flags |= PKT_FLAG_KEY; |
1253 |
pkt->pts = pts; |
1254 |
|
1255 |
return 0; |
1256 |
} |
1257 |
|
1258 |
static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) |
1259 |
{ |
1260 |
NUTContext *nut = s->priv_data; |
1261 |
ByteIOContext *bc = &s->pb; |
1262 |
int i, frame_code=0, ret; |
1263 |
|
1264 |
for(;;){
|
1265 |
int64_t pos= url_ftell(bc); |
1266 |
int frame_type= 0; |
1267 |
uint64_t tmp= nut->next_startcode; |
1268 |
nut->next_startcode=0;
|
1269 |
|
1270 |
if (url_feof(bc))
|
1271 |
return -1; |
1272 |
|
1273 |
if(tmp){
|
1274 |
pos-=8;
|
1275 |
}else{
|
1276 |
frame_code = get_byte(bc); |
1277 |
if(frame_code == 'N'){ |
1278 |
tmp= frame_code; |
1279 |
for(i=1; i<8; i++) |
1280 |
tmp = (tmp<<8) + get_byte(bc);
|
1281 |
} |
1282 |
} |
1283 |
switch(tmp){
|
1284 |
case MAIN_STARTCODE:
|
1285 |
case STREAM_STARTCODE:
|
1286 |
case INDEX_STARTCODE:
|
1287 |
get_packetheader(nut, bc, 0);
|
1288 |
assert(nut->packet_start[2] == pos);
|
1289 |
url_fseek(bc, nut->written_packet_size, SEEK_CUR); |
1290 |
break;
|
1291 |
case INFO_STARTCODE:
|
1292 |
if(decode_info_header(nut)<0) |
1293 |
goto resync;
|
1294 |
break;
|
1295 |
case KEYFRAME_STARTCODE:
|
1296 |
frame_type = 2;
|
1297 |
reset(s, get_v(bc)); |
1298 |
frame_code = get_byte(bc); |
1299 |
case 0: |
1300 |
ret= decode_frame(nut, pkt, frame_code, frame_type, pos); |
1301 |
if(ret==0) |
1302 |
return 0; |
1303 |
else if(ret==1) //ok but discard packet |
1304 |
break;
|
1305 |
default:
|
1306 |
resync:
|
1307 |
av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1); |
1308 |
tmp= find_any_startcode(bc, nut->packet_start[2]+1); |
1309 |
if(tmp==0) |
1310 |
return -1; |
1311 |
av_log(s, AV_LOG_DEBUG, "sync\n");
|
1312 |
nut->next_startcode= tmp; |
1313 |
} |
1314 |
} |
1315 |
} |
1316 |
|
1317 |
static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){ |
1318 |
NUTContext *nut = s->priv_data; |
1319 |
StreamContext *stream; |
1320 |
ByteIOContext *bc = &s->pb; |
1321 |
int64_t pos, pts; |
1322 |
uint64_t code; |
1323 |
int frame_code,step, stream_id, i,size, key_frame;
|
1324 |
av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit); |
1325 |
|
1326 |
if(*pos_arg < 0) |
1327 |
return AV_NOPTS_VALUE;
|
1328 |
|
1329 |
pos= *pos_arg; |
1330 |
step= FFMIN(16*1024, pos); |
1331 |
do{
|
1332 |
pos-= step; |
1333 |
code= find_any_startcode(bc, pos); |
1334 |
|
1335 |
if(code && url_ftell(bc) - 8 <= *pos_arg) |
1336 |
break;
|
1337 |
step= FFMIN(2*step, pos);
|
1338 |
}while(step);
|
1339 |
|
1340 |
if(!code) //nothing found, not even after pos_arg |
1341 |
return AV_NOPTS_VALUE;
|
1342 |
|
1343 |
url_fseek(bc, -8, SEEK_CUR);
|
1344 |
for(i=0; i<s->nb_streams; i++) |
1345 |
nut->stream[i].last_sync_pos= url_ftell(bc); |
1346 |
|
1347 |
for(;;){
|
1348 |
int frame_type=0; |
1349 |
int64_t pos= url_ftell(bc); |
1350 |
uint64_t tmp=0;
|
1351 |
|
1352 |
if(pos > pos_limit || url_feof(bc))
|
1353 |
return AV_NOPTS_VALUE;
|
1354 |
|
1355 |
frame_code = get_byte(bc); |
1356 |
if(frame_code == 'N'){ |
1357 |
tmp= frame_code; |
1358 |
for(i=1; i<8; i++) |
1359 |
tmp = (tmp<<8) + get_byte(bc);
|
1360 |
} |
1361 |
//av_log(s, AV_LOG_DEBUG, "before switch %llX at=%lld\n", tmp, pos);
|
1362 |
|
1363 |
switch(tmp){
|
1364 |
case MAIN_STARTCODE:
|
1365 |
case STREAM_STARTCODE:
|
1366 |
case INDEX_STARTCODE:
|
1367 |
case INFO_STARTCODE:
|
1368 |
get_packetheader(nut, bc, 0);
|
1369 |
assert(nut->packet_start[2]==pos);
|
1370 |
url_fseek(bc, nut->written_packet_size, SEEK_CUR); |
1371 |
break;
|
1372 |
case KEYFRAME_STARTCODE:
|
1373 |
frame_type=2;
|
1374 |
reset(s, get_v(bc)); |
1375 |
frame_code = get_byte(bc); |
1376 |
case 0: |
1377 |
size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, pos); |
1378 |
if(size < 0) |
1379 |
goto resync;
|
1380 |
|
1381 |
stream= &nut->stream[stream_id]; |
1382 |
if(stream_id != stream_index || !key_frame || pos < *pos_arg){
|
1383 |
url_fseek(bc, size, SEEK_CUR); |
1384 |
break;
|
1385 |
} |
1386 |
|
1387 |
*pos_arg= pos; |
1388 |
return pts;
|
1389 |
default:
|
1390 |
resync:
|
1391 |
av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1); |
1392 |
if(!find_any_startcode(bc, nut->packet_start[2]+1)) |
1393 |
return AV_NOPTS_VALUE;
|
1394 |
|
1395 |
url_fseek(bc, -8, SEEK_CUR);
|
1396 |
} |
1397 |
} |
1398 |
return AV_NOPTS_VALUE;
|
1399 |
} |
1400 |
|
1401 |
static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){ |
1402 |
// NUTContext *nut = s->priv_data;
|
1403 |
int64_t pos; |
1404 |
|
1405 |
if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0) |
1406 |
return -1; |
1407 |
|
1408 |
pos= url_ftell(&s->pb); |
1409 |
nut_read_timestamp(s, stream_index, &pos, pos-1);
|
1410 |
|
1411 |
return 0; |
1412 |
} |
1413 |
|
1414 |
static int nut_read_close(AVFormatContext *s) |
1415 |
{ |
1416 |
NUTContext *nut = s->priv_data; |
1417 |
|
1418 |
av_freep(&nut->stream); |
1419 |
|
1420 |
return 0; |
1421 |
} |
1422 |
|
1423 |
#ifdef CONFIG_NUT_DEMUXER
|
1424 |
AVInputFormat nut_demuxer = { |
1425 |
"nut",
|
1426 |
"nut format",
|
1427 |
sizeof(NUTContext),
|
1428 |
nut_probe, |
1429 |
nut_read_header, |
1430 |
nut_read_packet, |
1431 |
nut_read_close, |
1432 |
nut_read_seek, |
1433 |
nut_read_timestamp, |
1434 |
.extensions = "nut",
|
1435 |
}; |
1436 |
#endif
|
1437 |
#ifdef CONFIG_NUT_MUXER
|
1438 |
AVOutputFormat nut_muxer = { |
1439 |
"nut",
|
1440 |
"nut format",
|
1441 |
"video/x-nut",
|
1442 |
"nut",
|
1443 |
sizeof(NUTContext),
|
1444 |
#ifdef CONFIG_LIBVORBIS
|
1445 |
CODEC_ID_VORBIS, |
1446 |
#elif defined(CONFIG_MP3LAME)
|
1447 |
CODEC_ID_MP3, |
1448 |
#else
|
1449 |
CODEC_ID_MP2, /* AC3 needs liba52 decoder */
|
1450 |
#endif
|
1451 |
CODEC_ID_MPEG4, |
1452 |
nut_write_header, |
1453 |
nut_write_packet, |
1454 |
nut_write_trailer, |
1455 |
.flags = AVFMT_GLOBALHEADER, |
1456 |
}; |
1457 |
#endif
|