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