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 | static int64_t lsb2full(StreamContext *stream, int64_t lsb){
|
---|
398 | int64_t mask = (1<<stream->msb_timestamp_shift)-1;
|
---|
399 | int64_t delta= stream->last_pts - mask/2;
|
---|
400 | return ((lsb - delta)&mask) + delta;
|
---|
401 | }
|
---|
402 |
|
---|
403 | #ifdef CONFIG_MUXERS
|
---|
404 |
|
---|
405 | static void put_v(ByteIOContext *bc, uint64_t val)
|
---|
406 | {
|
---|
407 | int i;
|
---|
408 |
|
---|
409 | //av_log(NULL, AV_LOG_DEBUG, "put_v()= %lld\n", val);
|
---|
410 | val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently
|
---|
411 | i= get_length(val);
|
---|
412 |
|
---|
413 | for (i-=7; i>0; i-=7){
|
---|
414 | put_byte(bc, 0x80 | (val>>i));
|
---|
415 | }
|
---|
416 |
|
---|
417 | put_byte(bc, val&0x7f);
|
---|
418 | }
|
---|
419 |
|
---|
420 | /**
|
---|
421 | * stores a string as vb.
|
---|
422 | */
|
---|
423 | static void put_str(ByteIOContext *bc, const char *string){
|
---|
424 | int len= strlen(string);
|
---|
425 |
|
---|
426 | put_v(bc, len);
|
---|
427 | put_buffer(bc, string, len);
|
---|
428 | }
|
---|
429 |
|
---|
430 | static void put_s(ByteIOContext *bc, int64_t val){
|
---|
431 | if (val<=0) put_v(bc, -2*val );
|
---|
432 | else put_v(bc, 2*val-1);
|
---|
433 | }
|
---|
434 |
|
---|
435 | static void put_vb(ByteIOContext *bc, uint64_t val){
|
---|
436 | int i;
|
---|
437 |
|
---|
438 | for (i=8; val>>i; i+=8);
|
---|
439 |
|
---|
440 | put_v(bc, i>>3);
|
---|
441 | for(i-=8; i>=0; i-=8)
|
---|
442 | put_byte(bc, (val>>i)&0xFF);
|
---|
443 | }
|
---|
444 |
|
---|
445 | #ifdef TRACE
|
---|
446 | static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
|
---|
447 | printf("get_v %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
---|
448 |
|
---|
449 | put_v(bc, v);
|
---|
450 | }
|
---|
451 |
|
---|
452 | static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){
|
---|
453 | printf("get_s %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
---|
454 |
|
---|
455 | put_s(bc, v);
|
---|
456 | }
|
---|
457 |
|
---|
458 | static inline void put_vb_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
|
---|
459 | printf("get_vb %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
|
---|
460 |
|
---|
461 | put_vb(bc, v);
|
---|
462 | }
|
---|
463 | #define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
---|
464 | #define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
---|
465 | #define put_vb(bc, v) put_vb_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
---|
466 | #endif
|
---|
467 |
|
---|
468 | static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum)
|
---|
469 | {
|
---|
470 | put_flush_packet(bc);
|
---|
471 | nut->packet_start[2]= url_ftell(bc) - 8;
|
---|
472 | nut->written_packet_size = max_size;
|
---|
473 |
|
---|
474 | /* packet header */
|
---|
475 | put_v(bc, nut->written_packet_size); /* forward ptr */
|
---|
476 |
|
---|
477 | if(calculate_checksum)
|
---|
478 | init_checksum(bc, update_adler32, 0);
|
---|
479 |
|
---|
480 | return 0;
|
---|
481 | }
|
---|
482 |
|
---|
483 | /**
|
---|
484 | *
|
---|
485 | * must not be called more then once per packet
|
---|
486 | */
|
---|
487 | static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){
|
---|
488 | int64_t start= nut->packet_start[2];
|
---|
489 | int64_t cur= url_ftell(bc);
|
---|
490 | int size= cur - start - get_length(nut->written_packet_size)/7 - 8;
|
---|
491 |
|
---|
492 | if(calculate_checksum)
|
---|
493 | size += 4;
|
---|
494 |
|
---|
495 | if(size != nut->written_packet_size){
|
---|
496 | int i;
|
---|
497 |
|
---|
498 | assert( size <= nut->written_packet_size );
|
---|
499 |
|
---|
500 | url_fseek(bc, start + 8, SEEK_SET);
|
---|
501 | for(i=get_length(size); i < get_length(nut->written_packet_size); i+=7)
|
---|
502 | put_byte(bc, 0x80);
|
---|
503 | put_v(bc, size);
|
---|
504 |
|
---|
505 | url_fseek(bc, cur, SEEK_SET);
|
---|
506 | nut->written_packet_size= size; //FIXME may fail if multiple updates with differing sizes, as get_length may differ
|
---|
507 |
|
---|
508 | if(calculate_checksum)
|
---|
509 | put_be32(bc, get_checksum(bc));
|
---|
510 | }
|
---|
511 |
|
---|
512 | return 0;
|
---|
513 | }
|
---|
514 |
|
---|
515 | static int nut_write_header(AVFormatContext *s)
|
---|
516 | {
|
---|
517 | NUTContext *nut = s->priv_data;
|
---|
518 | ByteIOContext *bc = &s->pb;
|
---|
519 | AVCodecContext *codec;
|
---|
520 | int i, j, tmp_time, tmp_flags,tmp_stream, tmp_mul, tmp_size, tmp_fields;
|
---|
521 |
|
---|
522 | if (strcmp(s->filename, "./data/b-libav.nut")) {
|
---|
523 | av_log(s, AV_LOG_ERROR, " libavformat NUT is non-compliant and disabled\n");
|
---|
524 | return -1;
|
---|
525 | }
|
---|
526 |
|
---|
527 | nut->avf= s;
|
---|
528 |
|
---|
529 | nut->stream =
|
---|
530 | av_mallocz(sizeof(StreamContext)*s->nb_streams);
|
---|
531 |
|
---|
532 |
|
---|
533 | put_buffer(bc, ID_STRING, strlen(ID_STRING));
|
---|
534 | put_byte(bc, 0);
|
---|
535 | nut->packet_start[2]= url_ftell(bc);
|
---|
536 |
|
---|
537 | /* main header */
|
---|
538 | put_be64(bc, MAIN_STARTCODE);
|
---|
539 | put_packetheader(nut, bc, 120+5*256, 1);
|
---|
540 | put_v(bc, 2); /* version */
|
---|
541 | put_v(bc, s->nb_streams);
|
---|
542 | put_v(bc, MAX_DISTANCE);
|
---|
543 | put_v(bc, MAX_SHORT_DISTANCE);
|
---|
544 |
|
---|
545 | put_v(bc, nut->rate_num=1);
|
---|
546 | put_v(bc, nut->rate_den=2);
|
---|
547 | put_v(bc, nut->short_startcode=0x4EFE79);
|
---|
548 |
|
---|
549 | build_frame_code(s);
|
---|
550 | assert(nut->frame_code['N'].flags == FLAG_INVALID);
|
---|
551 |
|
---|
552 | tmp_time= tmp_flags= tmp_stream= tmp_mul= tmp_size= /*tmp_res=*/ INT_MAX;
|
---|
553 | for(i=0; i<256;){
|
---|
554 | tmp_fields=0;
|
---|
555 | tmp_size= 0;
|
---|
556 | if(tmp_time != nut->frame_code[i].timestamp_delta) tmp_fields=1;
|
---|
557 | if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2;
|
---|
558 | if(tmp_stream != nut->frame_code[i].stream_id_plus1) tmp_fields=3;
|
---|
559 | if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4;
|
---|
560 | // if(tmp_res != nut->frame_code[i].res ) tmp_fields=5;
|
---|
561 |
|
---|
562 | tmp_time = nut->frame_code[i].timestamp_delta;
|
---|
563 | tmp_flags = nut->frame_code[i].flags;
|
---|
564 | tmp_stream= nut->frame_code[i].stream_id_plus1;
|
---|
565 | tmp_mul = nut->frame_code[i].size_mul;
|
---|
566 | tmp_size = nut->frame_code[i].size_lsb;
|
---|
567 | // tmp_res = nut->frame_code[i].res;
|
---|
568 |
|
---|
569 | for(j=0; i<256; j++,i++){
|
---|
570 | if(nut->frame_code[i].timestamp_delta != tmp_time ) break;
|
---|
571 | if(nut->frame_code[i].flags != tmp_flags ) break;
|
---|
572 | if(nut->frame_code[i].stream_id_plus1 != tmp_stream) break;
|
---|
573 | if(nut->frame_code[i].size_mul != tmp_mul ) break;
|
---|
574 | if(nut->frame_code[i].size_lsb != tmp_size+j) break;
|
---|
575 | // if(nut->frame_code[i].res != tmp_res ) break;
|
---|
576 | }
|
---|
577 | if(j != tmp_mul - tmp_size) tmp_fields=6;
|
---|
578 |
|
---|
579 | put_v(bc, tmp_flags);
|
---|
580 | put_v(bc, tmp_fields);
|
---|
581 | if(tmp_fields>0) put_s(bc, tmp_time);
|
---|
582 | if(tmp_fields>1) put_v(bc, tmp_mul);
|
---|
583 | if(tmp_fields>2) put_v(bc, tmp_stream);
|
---|
584 | if(tmp_fields>3) put_v(bc, tmp_size);
|
---|
585 | if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/);
|
---|
586 | if(tmp_fields>5) put_v(bc, j);
|
---|
587 | }
|
---|
588 |
|
---|
589 | update_packetheader(nut, bc, 0, 1);
|
---|
590 |
|
---|
591 | /* stream headers */
|
---|
592 | for (i = 0; i < s->nb_streams; i++)
|
---|
593 | {
|
---|
594 | int nom, denom, ssize;
|
---|
595 |
|
---|
596 | codec = s->streams[i]->codec;
|
---|
597 |
|
---|
598 | put_be64(bc, STREAM_STARTCODE);
|
---|
599 | put_packetheader(nut, bc, 120 + codec->extradata_size, 1);
|
---|
600 | put_v(bc, i /*s->streams[i]->index*/);
|
---|
601 | switch(codec->codec_type){
|
---|
602 | case CODEC_TYPE_VIDEO: put_v(bc, 0); break;
|
---|
603 | case CODEC_TYPE_AUDIO: put_v(bc, 1); break;
|
---|
604 | // case CODEC_TYPE_TEXT : put_v(bc, 2); break;
|
---|
605 | case CODEC_TYPE_DATA : put_v(bc, 3); break;
|
---|
606 | default: return -1;
|
---|
607 | }
|
---|
608 | if (codec->codec_tag)
|
---|
609 | put_vb(bc, codec->codec_tag);
|
---|
610 | else if (codec->codec_type == CODEC_TYPE_VIDEO)
|
---|
611 | {
|
---|
612 | put_vb(bc, codec_get_bmp_tag(codec->codec_id));
|
---|
613 | }
|
---|
614 | else if (codec->codec_type == CODEC_TYPE_AUDIO)
|
---|
615 | {
|
---|
616 | put_vb(bc, codec_get_wav_tag(codec->codec_id));
|
---|
617 | }
|
---|
618 | else
|
---|
619 | put_vb(bc, 0);
|
---|
620 |
|
---|
621 | ff_parse_specific_params(codec, &nom, &ssize, &denom);
|
---|
622 |
|
---|
623 | nut->stream[i].rate_num= nom;
|
---|
624 | nut->stream[i].rate_den= denom;
|
---|
625 | av_set_pts_info(s->streams[i], 60, denom, nom);
|
---|
626 |
|
---|
627 | put_v(bc, codec->bit_rate);
|
---|
628 | put_vb(bc, 0); /* no language code */
|
---|
629 | put_v(bc, nom);
|
---|
630 | put_v(bc, denom);
|
---|
631 | if(nom / denom < 1000)
|
---|
632 | nut->stream[i].msb_timestamp_shift = 7;
|
---|
633 | else
|
---|
634 | nut->stream[i].msb_timestamp_shift = 14;
|
---|
635 | put_v(bc, nut->stream[i].msb_timestamp_shift);
|
---|
636 | put_v(bc, codec->has_b_frames);
|
---|
637 | put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */
|
---|
638 |
|
---|
639 | if(codec->extradata_size){
|
---|
640 | put_v(bc, 1);
|
---|
641 | put_v(bc, codec->extradata_size);
|
---|
642 | put_buffer(bc, codec->extradata, codec->extradata_size);
|
---|
643 | }
|
---|
644 | put_v(bc, 0); /* end of codec specific headers */
|
---|
645 |
|
---|
646 | switch(codec->codec_type)
|
---|
647 | {
|
---|
648 | case CODEC_TYPE_AUDIO:
|
---|
649 | put_v(bc, codec->sample_rate);
|
---|
650 | put_v(bc, 1);
|
---|
651 | put_v(bc, codec->channels);
|
---|
652 | break;
|
---|
653 | case CODEC_TYPE_VIDEO:
|
---|
654 | put_v(bc, codec->width);
|
---|
655 | put_v(bc, codec->height);
|
---|
656 | put_v(bc, codec->sample_aspect_ratio.num);
|
---|
657 | put_v(bc, codec->sample_aspect_ratio.den);
|
---|
658 | put_v(bc, 0); /* csp type -- unknown */
|
---|
659 | break;
|
---|
660 | default:
|
---|
661 | break;
|
---|
662 | }
|
---|
663 | update_packetheader(nut, bc, 0, 1);
|
---|
664 | }
|
---|
665 |
|
---|
666 | /* info header */
|
---|
667 | put_be64(bc, INFO_STARTCODE);
|
---|
668 | put_packetheader(nut, bc, 30+strlen(s->author)+strlen(s->title)+
|
---|
669 | strlen(s->comment)+strlen(s->copyright)+strlen(LIBAVFORMAT_IDENT), 1);
|
---|
670 | if (s->author[0])
|
---|
671 | {
|
---|
672 | put_v(bc, 9); /* type */
|
---|
673 | put_str(bc, s->author);
|
---|
674 | }
|
---|
675 | if (s->title[0])
|
---|
676 | {
|
---|
677 | put_v(bc, 10); /* type */
|
---|
678 | put_str(bc, s->title);
|
---|
679 | }
|
---|
680 | if (s->comment[0])
|
---|
681 | {
|
---|
682 | put_v(bc, 11); /* type */
|
---|
683 | put_str(bc, s->comment);
|
---|
684 | }
|
---|
685 | if (s->copyright[0])
|
---|
686 | {
|
---|
687 | put_v(bc, 12); /* type */
|
---|
688 | put_str(bc, s->copyright);
|
---|
689 | }
|
---|
690 | /* encoder */
|
---|
691 | if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)){
|
---|
692 | put_v(bc, 13); /* type */
|
---|
693 | put_str(bc, LIBAVFORMAT_IDENT);
|
---|
694 | }
|
---|
695 |
|
---|
696 | put_v(bc, 0); /* eof info */
|
---|
697 | update_packetheader(nut, bc, 0, 1);
|
---|
698 |
|
---|
699 | put_flush_packet(bc);
|
---|
700 |
|
---|
701 | return 0;
|
---|
702 | }
|
---|
703 |
|
---|
704 | static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
|
---|
705 | {
|
---|
706 | NUTContext *nut = s->priv_data;
|
---|
707 | StreamContext *stream= &nut->stream[pkt->stream_index];
|
---|
708 | ByteIOContext *bc = &s->pb;
|
---|
709 | int key_frame = 0, full_pts=0;
|
---|
710 | AVCodecContext *enc;
|
---|
711 | int64_t coded_pts;
|
---|
712 | int frame_type, best_length, frame_code, flags, i, size_mul, size_lsb, time_delta;
|
---|
713 | const int64_t frame_start= url_ftell(bc);
|
---|
714 | int64_t pts= pkt->pts;
|
---|
715 | int size= pkt->size;
|
---|
716 | int stream_index= pkt->stream_index;
|
---|
717 |
|
---|
718 | enc = s->streams[stream_index]->codec;
|
---|
719 | key_frame = !!(pkt->flags & PKT_FLAG_KEY);
|
---|
720 |
|
---|
721 | frame_type=0;
|
---|
722 | if(frame_start + size + 20 - FFMAX(nut->packet_start[1], nut->packet_start[2]) > MAX_DISTANCE)
|
---|
723 | frame_type=2;
|
---|
724 | if(key_frame && !stream->last_key_frame)
|
---|
725 | frame_type=2;
|
---|
726 |
|
---|
727 | if(frame_type>1){
|
---|
728 | int64_t global_ts= av_rescale(pts, stream->rate_den*(int64_t)nut->rate_num, stream->rate_num*(int64_t)nut->rate_den);
|
---|
729 | reset(s, global_ts);
|
---|
730 | put_be64(bc, KEYFRAME_STARTCODE);
|
---|
731 | put_v(bc, global_ts);
|
---|
732 | }
|
---|
733 | assert(stream->last_pts != AV_NOPTS_VALUE);
|
---|
734 | coded_pts = pts & ((1<<stream->msb_timestamp_shift)-1);
|
---|
735 | if(lsb2full(stream, coded_pts) != pts)
|
---|
736 | full_pts=1;
|
---|
737 |
|
---|
738 | if(full_pts)
|
---|
739 | coded_pts= pts + (1<<stream->msb_timestamp_shift);
|
---|
740 |
|
---|
741 | best_length=INT_MAX;
|
---|
742 | frame_code= -1;
|
---|
743 | for(i=0; i<256; i++){
|
---|
744 | int stream_id_plus1= nut->frame_code[i].stream_id_plus1;
|
---|
745 | int fc_key_frame;
|
---|
746 | int length=0;
|
---|
747 | size_mul= nut->frame_code[i].size_mul;
|
---|
748 | size_lsb= nut->frame_code[i].size_lsb;
|
---|
749 | time_delta= nut->frame_code[i].timestamp_delta;
|
---|
750 | flags= nut->frame_code[i].flags;
|
---|
751 |
|
---|
752 | assert(size_mul > size_lsb);
|
---|
753 |
|
---|
754 | if(stream_id_plus1 == 0) length+= get_length(stream_index);
|
---|
755 | else if(stream_id_plus1 - 1 != stream_index)
|
---|
756 | continue;
|
---|
757 | fc_key_frame= !!(flags & FLAG_KEY_FRAME);
|
---|
758 |
|
---|
759 | assert(key_frame==0 || key_frame==1);
|
---|
760 | if(fc_key_frame != key_frame)
|
---|
761 | continue;
|
---|
762 |
|
---|
763 | if(flags & FLAG_DATA_SIZE){
|
---|
764 | if(size % size_mul != size_lsb)
|
---|
765 | continue;
|
---|
766 | length += get_length(size / size_mul);
|
---|
767 | }else if(size != size_lsb)
|
---|
768 | continue;
|
---|
769 |
|
---|
770 | if(full_pts && time_delta)
|
---|
771 | continue;
|
---|
772 |
|
---|
773 | if(!time_delta){
|
---|
774 | length += get_length(coded_pts);
|
---|
775 | }else{
|
---|
776 | if(time_delta != pts - stream->last_pts)
|
---|
777 | continue;
|
---|
778 | }
|
---|
779 |
|
---|
780 | if(length < best_length){
|
---|
781 | best_length= length;
|
---|
782 | frame_code=i;
|
---|
783 | }
|
---|
784 | // 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);
|
---|
785 | }
|
---|
786 |
|
---|
787 | assert(frame_code != -1);
|
---|
788 | flags= nut->frame_code[frame_code].flags;
|
---|
789 | size_mul= nut->frame_code[frame_code].size_mul;
|
---|
790 | size_lsb= nut->frame_code[frame_code].size_lsb;
|
---|
791 | time_delta= nut->frame_code[frame_code].timestamp_delta;
|
---|
792 | #ifdef TRACE
|
---|
793 | best_length /= 7;
|
---|
794 | best_length ++; //frame_code
|
---|
795 | if(frame_type==2){
|
---|
796 | best_length += 8; // startcode
|
---|
797 | }
|
---|
798 | 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);
|
---|
799 | // 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]);
|
---|
800 | #endif
|
---|
801 |
|
---|
802 | assert(frame_type != 1); //short startcode not implemented yet
|
---|
803 | put_byte(bc, frame_code);
|
---|
804 |
|
---|
805 | if(nut->frame_code[frame_code].stream_id_plus1 == 0)
|
---|
806 | put_v(bc, stream_index);
|
---|
807 | if (!time_delta){
|
---|
808 | put_v(bc, coded_pts);
|
---|
809 | }
|
---|
810 | if(flags & FLAG_DATA_SIZE)
|
---|
811 | put_v(bc, size / size_mul);
|
---|
812 | else
|
---|
813 | assert(size == size_lsb);
|
---|
814 | if(size > MAX_DISTANCE){
|
---|
815 | assert(frame_type > 1);
|
---|
816 | }
|
---|
817 |
|
---|
818 | put_buffer(bc, pkt->data, size);
|
---|
819 |
|
---|
820 | update(nut, stream_index, frame_start, frame_type, frame_code, key_frame, size, pts);
|
---|
821 |
|
---|
822 | return 0;
|
---|
823 | }
|
---|
824 |
|
---|
825 | static int nut_write_trailer(AVFormatContext *s)
|
---|
826 | {
|
---|
827 | NUTContext *nut = s->priv_data;
|
---|
828 | ByteIOContext *bc = &s->pb;
|
---|
829 |
|
---|
830 | #if 0
|
---|
831 | int i;
|
---|
832 |
|
---|
833 | /* WRITE INDEX */
|
---|
834 |
|
---|
835 | for (i = 0; s->nb_streams; i++)
|
---|
836 | {
|
---|
837 | put_be64(bc, INDEX_STARTCODE);
|
---|
838 | put_packetheader(nut, bc, 64, 1);
|
---|
839 | put_v(bc, s->streams[i]->id);
|
---|
840 | put_v(bc, ...);
|
---|
841 | update_packetheader(nut, bc, 0, 1);
|
---|
842 | }
|
---|
843 | #endif
|
---|
844 |
|
---|
845 | put_flush_packet(bc);
|
---|
846 |
|
---|
847 | av_freep(&nut->stream);
|
---|
848 |
|
---|
849 | return 0;
|
---|
850 | }
|
---|
851 | #endif //CONFIG_MUXERS
|
---|
852 |
|
---|
853 | static int nut_probe(AVProbeData *p)
|
---|
854 | {
|
---|
855 | int i;
|
---|
856 | uint64_t code= 0xff;
|
---|
857 |
|
---|
858 | for (i = 0; i < p->buf_size; i++) {
|
---|
859 | code = (code << 8) | p->buf[i];
|
---|
860 | if (code == MAIN_STARTCODE)
|
---|
861 | return AVPROBE_SCORE_MAX;
|
---|
862 | }
|
---|
863 | return 0;
|
---|
864 | }
|
---|
865 |
|
---|
866 | static int decode_main_header(NUTContext *nut){
|
---|
867 | AVFormatContext *s= nut->avf;
|
---|
868 | ByteIOContext *bc = &s->pb;
|
---|
869 | uint64_t tmp;
|
---|
870 | int i, j, tmp_stream, tmp_mul, tmp_time, tmp_size, count, tmp_res;
|
---|
871 |
|
---|
872 | get_packetheader(nut, bc, 1);
|
---|
873 |
|
---|
874 | tmp = get_v(bc);
|
---|
875 | if (tmp != 2){
|
---|
876 | av_log(s, AV_LOG_ERROR, "bad version (%"PRId64")\n", tmp);
|
---|
877 | return -1;
|
---|
878 | }
|
---|
879 |
|
---|
880 | nut->stream_count = get_v(bc);
|
---|
881 | if(nut->stream_count > MAX_STREAMS){
|
---|
882 | av_log(s, AV_LOG_ERROR, "too many streams\n");
|
---|
883 | return -1;
|
---|
884 | }
|
---|
885 | nut->max_distance = get_v(bc);
|
---|
886 | nut->max_short_distance = get_v(bc);
|
---|
887 | nut->rate_num= get_v(bc);
|
---|
888 | nut->rate_den= get_v(bc);
|
---|
889 | nut->short_startcode= get_v(bc);
|
---|
890 | if(nut->short_startcode>>16 != 'N'){
|
---|
891 | av_log(s, AV_LOG_ERROR, "invalid short startcode %X\n", nut->short_startcode);
|
---|
892 | return -1;
|
---|
893 | }
|
---|
894 |
|
---|
895 | for(i=0; i<256;){
|
---|
896 | int tmp_flags = get_v(bc);
|
---|
897 | int tmp_fields= get_v(bc);
|
---|
898 | if(tmp_fields>0) tmp_time = get_s(bc);
|
---|
899 | if(tmp_fields>1) tmp_mul = get_v(bc);
|
---|
900 | if(tmp_fields>2) tmp_stream= get_v(bc);
|
---|
901 | if(tmp_fields>3) tmp_size = get_v(bc);
|
---|
902 | else tmp_size = 0;
|
---|
903 | if(tmp_fields>4) tmp_res = get_v(bc);
|
---|
904 | else tmp_res = 0;
|
---|
905 | if(tmp_fields>5) count = get_v(bc);
|
---|
906 | else count = tmp_mul - tmp_size;
|
---|
907 |
|
---|
908 | while(tmp_fields-- > 6)
|
---|
909 | get_v(bc);
|
---|
910 |
|
---|
911 | if(count == 0 || i+count > 256){
|
---|
912 | av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i);
|
---|
913 | return -1;
|
---|
914 | }
|
---|
915 | if(tmp_stream > nut->stream_count + 1){
|
---|
916 | av_log(s, AV_LOG_ERROR, "illegal stream number\n");
|
---|
917 | return -1;
|
---|
918 | }
|
---|
919 |
|
---|
920 | for(j=0; j<count; j++,i++){
|
---|
921 | nut->frame_code[i].flags = tmp_flags ;
|
---|
922 | nut->frame_code[i].timestamp_delta = tmp_time ;
|
---|
923 | nut->frame_code[i].stream_id_plus1 = tmp_stream;
|
---|
924 | nut->frame_code[i].size_mul = tmp_mul ;
|
---|
925 | nut->frame_code[i].size_lsb = tmp_size+j;
|
---|
926 | nut->frame_code[i].reserved_count = tmp_res ;
|
---|
927 | }
|
---|
928 | }
|
---|
929 | if(nut->frame_code['N'].flags != FLAG_INVALID){
|
---|
930 | av_log(s, AV_LOG_ERROR, "illegal frame_code table\n");
|
---|
931 | return -1;
|
---|
932 | }
|
---|
933 |
|
---|
934 | if(check_checksum(bc)){
|
---|
935 | av_log(s, AV_LOG_ERROR, "Main header checksum mismatch\n");
|
---|
936 | return -1;
|
---|
937 | }
|
---|
938 |
|
---|
939 | return 0;
|
---|
940 | }
|
---|
941 |
|
---|
942 | static int decode_stream_header(NUTContext *nut){
|
---|
943 | AVFormatContext *s= nut->avf;
|
---|
944 | ByteIOContext *bc = &s->pb;
|
---|
945 | int class, nom, denom, stream_id;
|
---|
946 | uint64_t tmp;
|
---|
947 | AVStream *st;
|
---|
948 |
|
---|
949 | get_packetheader(nut, bc, 1);
|
---|
950 | stream_id= get_v(bc);
|
---|
951 | if(stream_id >= nut->stream_count || s->streams[stream_id])
|
---|
952 | return -1;
|
---|
953 |
|
---|
954 | st = av_new_stream(s, stream_id);
|
---|
955 | if (!st)
|
---|
956 | return AVERROR_NOMEM;
|
---|
957 |
|
---|
958 | class = get_v(bc);
|
---|
959 | tmp = get_vb(bc);
|
---|
960 | st->codec->codec_tag= tmp;
|
---|
961 | switch(class)
|
---|
962 | {
|
---|
963 | case 0:
|
---|
964 | st->codec->codec_type = CODEC_TYPE_VIDEO;
|
---|
965 | st->codec->codec_id = codec_get_bmp_id(tmp);
|
---|
966 | if (st->codec->codec_id == CODEC_ID_NONE)
|
---|
967 | av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
|
---|
968 | break;
|
---|
969 | case 1:
|
---|
970 | case 32: //compatibility
|
---|
971 | st->codec->codec_type = CODEC_TYPE_AUDIO;
|
---|
972 | st->codec->codec_id = codec_get_wav_id(tmp);
|
---|
973 | if (st->codec->codec_id == CODEC_ID_NONE)
|
---|
974 | av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
|
---|
975 | break;
|
---|
976 | case 2:
|
---|
977 | // st->codec->codec_type = CODEC_TYPE_TEXT;
|
---|
978 | // break;
|
---|
979 | case 3:
|
---|
980 | st->codec->codec_type = CODEC_TYPE_DATA;
|
---|
981 | break;
|
---|
982 | default:
|
---|
983 | av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class);
|
---|
984 | return -1;
|
---|
985 | }
|
---|
986 | s->bit_rate += get_v(bc);
|
---|
987 | get_vb(bc); /* language code */
|
---|
988 | nom = get_v(bc);
|
---|
989 | denom = get_v(bc);
|
---|
990 | nut->stream[stream_id].msb_timestamp_shift = get_v(bc);
|
---|
991 | st->codec->has_b_frames=
|
---|
992 | nut->stream[stream_id].decode_delay= get_v(bc);
|
---|
993 | get_byte(bc); /* flags */
|
---|
994 |
|
---|
995 | /* codec specific data headers */
|
---|
996 | while(get_v(bc) != 0){
|
---|
997 | st->codec->extradata_size= get_v(bc);
|
---|
998 | if((unsigned)st->codec->extradata_size > (1<<30))
|
---|
999 | return -1;
|
---|
1000 | st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
---|
1001 | get_buffer(bc, st->codec->extradata, st->codec->extradata_size);
|
---|
1002 | // url_fskip(bc, get_v(bc));
|
---|
1003 | }
|
---|
1004 |
|
---|
1005 | if (st->codec->codec_type == CODEC_TYPE_VIDEO) /* VIDEO */
|
---|
1006 | {
|
---|
1007 | st->codec->width = get_v(bc);
|
---|
1008 | st->codec->height = get_v(bc);
|
---|
1009 | st->codec->sample_aspect_ratio.num= get_v(bc);
|
---|
1010 | st->codec->sample_aspect_ratio.den= get_v(bc);
|
---|
1011 | get_v(bc); /* csp type */
|
---|
1012 | }
|
---|
1013 | if (st->codec->codec_type == CODEC_TYPE_AUDIO) /* AUDIO */
|
---|
1014 | {
|
---|
1015 | st->codec->sample_rate = get_v(bc);
|
---|
1016 | get_v(bc); // samplerate_den
|
---|
1017 | st->codec->channels = get_v(bc);
|
---|
1018 | }
|
---|
1019 | if(check_checksum(bc)){
|
---|
1020 | av_log(s, AV_LOG_ERROR, "Stream header %d checksum mismatch\n", stream_id);
|
---|
1021 | return -1;
|
---|
1022 | }
|
---|
1023 | av_set_pts_info(s->streams[stream_id], 60, denom, nom);
|
---|
1024 | nut->stream[stream_id].rate_num= nom;
|
---|
1025 | nut->stream[stream_id].rate_den= denom;
|
---|
1026 | return 0;
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | static int decode_info_header(NUTContext *nut){
|
---|
1030 | AVFormatContext *s= nut->avf;
|
---|
1031 | ByteIOContext *bc = &s->pb;
|
---|
1032 |
|
---|
1033 | get_packetheader(nut, bc, 1);
|
---|
1034 |
|
---|
1035 | for(;;){
|
---|
1036 | int id= get_v(bc);
|
---|
1037 | char *name, *type, custom_name[256], custom_type[256];
|
---|
1038 |
|
---|
1039 | if(!id)
|
---|
1040 | break;
|
---|
1041 | else if(id >= sizeof(info_table)/sizeof(info_table[0])){
|
---|
1042 | av_log(s, AV_LOG_ERROR, "info id is too large %d %zd\n", id, sizeof(info_table)/sizeof(info_table[0]));
|
---|
1043 | return -1;
|
---|
1044 | }
|
---|
1045 |
|
---|
1046 | type= info_table[id][1];
|
---|
1047 | name= info_table[id][0];
|
---|
1048 | //av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name);
|
---|
1049 |
|
---|
1050 | if(!type){
|
---|
1051 | get_str(bc, custom_type, sizeof(custom_type));
|
---|
1052 | type= custom_type;
|
---|
1053 | }
|
---|
1054 | if(!name){
|
---|
1055 | get_str(bc, custom_name, sizeof(custom_name));
|
---|
1056 | name= custom_name;
|
---|
1057 | }
|
---|
1058 |
|
---|
1059 | if(!strcmp(type, "v")){
|
---|
1060 | get_v(bc);
|
---|
1061 | }else{
|
---|
1062 | if(!strcmp(name, "Author"))
|
---|
1063 | get_str(bc, s->author, sizeof(s->author));
|
---|
1064 | else if(!strcmp(name, "Title"))
|
---|
1065 | get_str(bc, s->title, sizeof(s->title));
|
---|
1066 | else if(!strcmp(name, "Copyright"))
|
---|
1067 | get_str(bc, s->copyright, sizeof(s->copyright));
|
---|
1068 | else if(!strcmp(name, "Description"))
|
---|
1069 | get_str(bc, s->comment, sizeof(s->comment));
|
---|
1070 | else
|
---|
1071 | get_str(bc, NULL, 0);
|
---|
1072 | }
|
---|
1073 | }
|
---|
1074 | if(check_checksum(bc)){
|
---|
1075 | av_log(s, AV_LOG_ERROR, "Info header checksum mismatch\n");
|
---|
1076 | return -1;
|
---|
1077 | }
|
---|
1078 | return 0;
|
---|
1079 | }
|
---|
1080 |
|
---|
1081 | static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
|
---|
1082 | {
|
---|
1083 | NUTContext *nut = s->priv_data;
|
---|
1084 | ByteIOContext *bc = &s->pb;
|
---|
1085 | int64_t pos;
|
---|
1086 | int inited_stream_count;
|
---|
1087 |
|
---|
1088 | nut->avf= s;
|
---|
1089 |
|
---|
1090 | /* main header */
|
---|
1091 | pos=0;
|
---|
1092 | for(;;){
|
---|
1093 | pos= find_startcode(bc, MAIN_STARTCODE, pos)+1;
|
---|
1094 | if (pos<0){
|
---|
1095 | av_log(s, AV_LOG_ERROR, "no main startcode found\n");
|
---|
1096 | return -1;
|
---|
1097 | }
|
---|
1098 | if(decode_main_header(nut) >= 0)
|
---|
1099 | break;
|
---|
1100 | }
|
---|
1101 |
|
---|
1102 |
|
---|
1103 | s->bit_rate = 0;
|
---|
1104 |
|
---|
1105 | nut->stream = av_malloc(sizeof(StreamContext)*nut->stream_count);
|
---|
1106 |
|
---|
1107 | /* stream headers */
|
---|
1108 | pos=0;
|
---|
1109 | for(inited_stream_count=0; inited_stream_count < nut->stream_count;){
|
---|
1110 | pos= find_startcode(bc, STREAM_STARTCODE, pos)+1;
|
---|
1111 | if (pos<0+1){
|
---|
1112 | av_log(s, AV_LOG_ERROR, "not all stream headers found\n");
|
---|
1113 | return -1;
|
---|
1114 | }
|
---|
1115 | if(decode_stream_header(nut) >= 0)
|
---|
1116 | inited_stream_count++;
|
---|
1117 | }
|
---|
1118 |
|
---|
1119 | /* info headers */
|
---|
1120 | pos=0;
|
---|
1121 | for(;;){
|
---|
1122 | uint64_t startcode= find_any_startcode(bc, pos);
|
---|
1123 | pos= url_ftell(bc);
|
---|
1124 |
|
---|
1125 | if(startcode==0){
|
---|
1126 | av_log(s, AV_LOG_ERROR, "EOF before video frames\n");
|
---|
1127 | return -1;
|
---|
1128 | }else if(startcode == KEYFRAME_STARTCODE){
|
---|
1129 | nut->next_startcode= startcode;
|
---|
1130 | break;
|
---|
1131 | }else if(startcode != INFO_STARTCODE){
|
---|
1132 | continue;
|
---|
1133 | }
|
---|
1134 |
|
---|
1135 | decode_info_header(nut);
|
---|
1136 | }
|
---|
1137 |
|
---|
1138 | return 0;
|
---|
1139 | }
|
---|
1140 |
|
---|
1141 | 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){
|
---|
1142 | AVFormatContext *s= nut->avf;
|
---|
1143 | StreamContext *stream;
|
---|
1144 | ByteIOContext *bc = &s->pb;
|
---|
1145 | int size, flags, size_mul, size_lsb, stream_id, time_delta;
|
---|
1146 | int64_t pts = 0;
|
---|
1147 |
|
---|
1148 | if(frame_type < 2 && frame_start - nut->packet_start[2] > nut->max_distance){
|
---|
1149 | av_log(s, AV_LOG_ERROR, "last frame must have been damaged\n");
|
---|
1150 | return -1;
|
---|
1151 | }
|
---|
1152 |
|
---|
1153 | if(frame_type)
|
---|
1154 | nut->packet_start[ frame_type ]= frame_start; //otherwise 1 goto 1 may happen
|
---|
1155 |
|
---|
1156 | flags= nut->frame_code[frame_code].flags;
|
---|
1157 | size_mul= nut->frame_code[frame_code].size_mul;
|
---|
1158 | size_lsb= nut->frame_code[frame_code].size_lsb;
|
---|
1159 | stream_id= nut->frame_code[frame_code].stream_id_plus1 - 1;
|
---|
1160 | time_delta= nut->frame_code[frame_code].timestamp_delta;
|
---|
1161 |
|
---|
1162 | if(stream_id==-1)
|
---|
1163 | stream_id= get_v(bc);
|
---|
1164 | if(stream_id >= s->nb_streams){
|
---|
1165 | av_log(s, AV_LOG_ERROR, "illegal stream_id\n");
|
---|
1166 | return -1;
|
---|
1167 | }
|
---|
1168 | stream= &nut->stream[stream_id];
|
---|
1169 |
|
---|
1170 | // 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]);
|
---|
1171 |
|
---|
1172 | *key_frame_ret= !!(flags & FLAG_KEY_FRAME);
|
---|
1173 |
|
---|
1174 | if(!time_delta){
|
---|
1175 | int64_t mask = (1<<stream->msb_timestamp_shift)-1;
|
---|
1176 | pts= get_v(bc);
|
---|
1177 | if(pts > mask){
|
---|
1178 | pts -= mask+1;
|
---|
1179 | }else{
|
---|
1180 | if(stream->last_pts == AV_NOPTS_VALUE){
|
---|
1181 | av_log(s, AV_LOG_ERROR, "no reference pts available\n");
|
---|
1182 | return -1;
|
---|
1183 | }
|
---|
1184 | pts= lsb2full(stream, pts);
|
---|
1185 | }
|
---|
1186 | }else{
|
---|
1187 | if(stream->last_pts == AV_NOPTS_VALUE){
|
---|
1188 | av_log(s, AV_LOG_ERROR, "no reference pts available\n");
|
---|
1189 | return -1;
|
---|
1190 | }
|
---|
1191 | pts= stream->last_pts + time_delta;
|
---|
1192 | }
|
---|
1193 |
|
---|
1194 | if(*key_frame_ret){
|
---|
1195 | // 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);
|
---|
1196 | av_add_index_entry(
|
---|
1197 | s->streams[stream_id],
|
---|
1198 | frame_start,
|
---|
1199 | pts,
|
---|
1200 | 0,
|
---|
1201 | frame_start - nut->stream[stream_id].last_sync_pos,
|
---|
1202 | AVINDEX_KEYFRAME);
|
---|
1203 | nut->stream[stream_id].last_sync_pos= frame_start;
|
---|
1204 | // assert(nut->packet_start == frame_start);
|
---|
1205 | }
|
---|
1206 |
|
---|
1207 | assert(size_mul > size_lsb);
|
---|
1208 | size= size_lsb;
|
---|
1209 | if(flags & FLAG_DATA_SIZE)
|
---|
1210 | size+= size_mul*get_v(bc);
|
---|
1211 |
|
---|
1212 | #ifdef TRACE
|
---|
1213 | 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);
|
---|
1214 | #endif
|
---|
1215 |
|
---|
1216 | if(frame_type==0 && url_ftell(bc) - nut->packet_start[2] + size > nut->max_distance){
|
---|
1217 | av_log(s, AV_LOG_ERROR, "frame size too large\n");
|
---|
1218 | return -1;
|
---|
1219 | }
|
---|
1220 |
|
---|
1221 | *stream_id_ret = stream_id;
|
---|
1222 | *pts_ret = pts;
|
---|
1223 |
|
---|
1224 | update(nut, stream_id, frame_start, frame_type, frame_code, *key_frame_ret, size, pts);
|
---|
1225 |
|
---|
1226 | return size;
|
---|
1227 | }
|
---|
1228 |
|
---|
1229 | static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type, int64_t frame_start){
|
---|
1230 | AVFormatContext *s= nut->avf;
|
---|
1231 | ByteIOContext *bc = &s->pb;
|
---|
1232 | int size, stream_id, key_frame, discard;
|
---|
1233 | int64_t pts, last_IP_pts;
|
---|
1234 |
|
---|
1235 | size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, frame_start);
|
---|
1236 | if(size < 0)
|
---|
1237 | return -1;
|
---|
1238 |
|
---|
1239 | discard= s->streams[ stream_id ]->discard;
|
---|
1240 | last_IP_pts= s->streams[ stream_id ]->last_IP_pts;
|
---|
1241 | if( (discard >= AVDISCARD_NONKEY && !key_frame)
|
---|
1242 | ||(discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE && last_IP_pts > pts)
|
---|
1243 | || discard >= AVDISCARD_ALL){
|
---|
1244 | url_fskip(bc, size);
|
---|
1245 | return 1;
|
---|
1246 | }
|
---|
1247 |
|
---|
1248 | av_get_packet(bc, pkt, size);
|
---|
1249 | pkt->stream_index = stream_id;
|
---|
1250 | if (key_frame)
|
---|
1251 | pkt->flags |= PKT_FLAG_KEY;
|
---|
1252 | pkt->pts = pts;
|
---|
1253 |
|
---|
1254 | return 0;
|
---|
1255 | }
|
---|
1256 |
|
---|
1257 | static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
|
---|
1258 | {
|
---|
1259 | NUTContext *nut = s->priv_data;
|
---|
1260 | ByteIOContext *bc = &s->pb;
|
---|
1261 | int i, frame_code=0, ret;
|
---|
1262 |
|
---|
1263 | for(;;){
|
---|
1264 | int64_t pos= url_ftell(bc);
|
---|
1265 | int frame_type= 0;
|
---|
1266 | uint64_t tmp= nut->next_startcode;
|
---|
1267 | nut->next_startcode=0;
|
---|
1268 |
|
---|
1269 | if (url_feof(bc))
|
---|
1270 | return -1;
|
---|
1271 |
|
---|
1272 | if(tmp){
|
---|
1273 | pos-=8;
|
---|
1274 | }else{
|
---|
1275 | frame_code = get_byte(bc);
|
---|
1276 | if(frame_code == 'N'){
|
---|
1277 | tmp= frame_code;
|
---|
1278 | for(i=1; i<8; i++)
|
---|
1279 | tmp = (tmp<<8) + get_byte(bc);
|
---|
1280 | }
|
---|
1281 | }
|
---|
1282 | switch(tmp){
|
---|
1283 | case MAIN_STARTCODE:
|
---|
1284 | case STREAM_STARTCODE:
|
---|
1285 | case INDEX_STARTCODE:
|
---|
1286 | get_packetheader(nut, bc, 0);
|
---|
1287 | assert(nut->packet_start[2] == pos);
|
---|
1288 | url_fseek(bc, nut->written_packet_size, SEEK_CUR);
|
---|
1289 | break;
|
---|
1290 | case INFO_STARTCODE:
|
---|
1291 | if(decode_info_header(nut)<0)
|
---|
1292 | goto resync;
|
---|
1293 | break;
|
---|
1294 | case KEYFRAME_STARTCODE:
|
---|
1295 | frame_type = 2;
|
---|
1296 | reset(s, get_v(bc));
|
---|
1297 | frame_code = get_byte(bc);
|
---|
1298 | case 0:
|
---|
1299 | ret= decode_frame(nut, pkt, frame_code, frame_type, pos);
|
---|
1300 | if(ret==0)
|
---|
1301 | return 0;
|
---|
1302 | else if(ret==1) //ok but discard packet
|
---|
1303 | break;
|
---|
1304 | default:
|
---|
1305 | resync:
|
---|
1306 | av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1);
|
---|
1307 | tmp= find_any_startcode(bc, nut->packet_start[2]+1);
|
---|
1308 | if(tmp==0)
|
---|
1309 | return -1;
|
---|
1310 | av_log(s, AV_LOG_DEBUG, "sync\n");
|
---|
1311 | nut->next_startcode= tmp;
|
---|
1312 | }
|
---|
1313 | }
|
---|
1314 | }
|
---|
1315 |
|
---|
1316 | static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
|
---|
1317 | NUTContext *nut = s->priv_data;
|
---|
1318 | StreamContext *stream;
|
---|
1319 | ByteIOContext *bc = &s->pb;
|
---|
1320 | int64_t pos, pts;
|
---|
1321 | uint64_t code;
|
---|
1322 | int frame_code,step, stream_id, i,size, key_frame;
|
---|
1323 | av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit);
|
---|
1324 |
|
---|
1325 | if(*pos_arg < 0)
|
---|
1326 | return AV_NOPTS_VALUE;
|
---|
1327 |
|
---|
1328 | pos= *pos_arg;
|
---|
1329 | step= FFMIN(16*1024, pos);
|
---|
1330 | do{
|
---|
1331 | pos-= step;
|
---|
1332 | code= find_any_startcode(bc, pos);
|
---|
1333 |
|
---|
1334 | if(code && url_ftell(bc) - 8 <= *pos_arg)
|
---|
1335 | break;
|
---|
1336 | step= FFMIN(2*step, pos);
|
---|
1337 | }while(step);
|
---|
1338 |
|
---|
1339 | if(!code) //nothing found, not even after pos_arg
|
---|
1340 | return AV_NOPTS_VALUE;
|
---|
1341 |
|
---|
1342 | url_fseek(bc, -8, SEEK_CUR);
|
---|
1343 | for(i=0; i<s->nb_streams; i++)
|
---|
1344 | nut->stream[i].last_sync_pos= url_ftell(bc);
|
---|
1345 |
|
---|
1346 | for(;;){
|
---|
1347 | int frame_type=0;
|
---|
1348 | int64_t pos= url_ftell(bc);
|
---|
1349 | uint64_t tmp=0;
|
---|
1350 |
|
---|
1351 | if(pos > pos_limit || url_feof(bc))
|
---|
1352 | return AV_NOPTS_VALUE;
|
---|
1353 |
|
---|
1354 | frame_code = get_byte(bc);
|
---|
1355 | if(frame_code == 'N'){
|
---|
1356 | tmp= frame_code;
|
---|
1357 | for(i=1; i<8; i++)
|
---|
1358 | tmp = (tmp<<8) + get_byte(bc);
|
---|
1359 | }
|
---|
1360 | //av_log(s, AV_LOG_DEBUG, "before switch %llX at=%lld\n", tmp, pos);
|
---|
1361 |
|
---|
1362 | switch(tmp){
|
---|
1363 | case MAIN_STARTCODE:
|
---|
1364 | case STREAM_STARTCODE:
|
---|
1365 | case INDEX_STARTCODE:
|
---|
1366 | case INFO_STARTCODE:
|
---|
1367 | get_packetheader(nut, bc, 0);
|
---|
1368 | assert(nut->packet_start[2]==pos);
|
---|
1369 | url_fseek(bc, nut->written_packet_size, SEEK_CUR);
|
---|
1370 | break;
|
---|
1371 | case KEYFRAME_STARTCODE:
|
---|
1372 | frame_type=2;
|
---|
1373 | reset(s, get_v(bc));
|
---|
1374 | frame_code = get_byte(bc);
|
---|
1375 | case 0:
|
---|
1376 | size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, pos);
|
---|
1377 | if(size < 0)
|
---|
1378 | goto resync;
|
---|
1379 |
|
---|
1380 | stream= &nut->stream[stream_id];
|
---|
1381 | if(stream_id != stream_index || !key_frame || pos < *pos_arg){
|
---|
1382 | url_fseek(bc, size, SEEK_CUR);
|
---|
1383 | break;
|
---|
1384 | }
|
---|
1385 |
|
---|
1386 | *pos_arg= pos;
|
---|
1387 | return pts;
|
---|
1388 | default:
|
---|
1389 | resync:
|
---|
1390 | av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1);
|
---|
1391 | if(!find_any_startcode(bc, nut->packet_start[2]+1))
|
---|
1392 | return AV_NOPTS_VALUE;
|
---|
1393 |
|
---|
1394 | url_fseek(bc, -8, SEEK_CUR);
|
---|
1395 | }
|
---|
1396 | }
|
---|
1397 | return AV_NOPTS_VALUE;
|
---|
1398 | }
|
---|
1399 |
|
---|
1400 | static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
|
---|
1401 | // NUTContext *nut = s->priv_data;
|
---|
1402 | int64_t pos;
|
---|
1403 |
|
---|
1404 | if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
|
---|
1405 | return -1;
|
---|
1406 |
|
---|
1407 | pos= url_ftell(&s->pb);
|
---|
1408 | nut_read_timestamp(s, stream_index, &pos, pos-1);
|
---|
1409 |
|
---|
1410 | return 0;
|
---|
1411 | }
|
---|
1412 |
|
---|
1413 | static int nut_read_close(AVFormatContext *s)
|
---|
1414 | {
|
---|
1415 | NUTContext *nut = s->priv_data;
|
---|
1416 |
|
---|
1417 | av_freep(&nut->stream);
|
---|
1418 |
|
---|
1419 | return 0;
|
---|
1420 | }
|
---|
1421 |
|
---|
1422 | static AVInputFormat nut_demuxer = {
|
---|
1423 | "nut",
|
---|
1424 | "nut format",
|
---|
1425 | sizeof(NUTContext),
|
---|
1426 | nut_probe,
|
---|
1427 | nut_read_header,
|
---|
1428 | nut_read_packet,
|
---|
1429 | nut_read_close,
|
---|
1430 | nut_read_seek,
|
---|
1431 | nut_read_timestamp,
|
---|
1432 | .extensions = "nut",
|
---|
1433 | };
|
---|
1434 |
|
---|
1435 | #ifdef CONFIG_MUXERS
|
---|
1436 | static AVOutputFormat nut_muxer = {
|
---|
1437 | "nut",
|
---|
1438 | "nut format",
|
---|
1439 | "video/x-nut",
|
---|
1440 | "nut",
|
---|
1441 | sizeof(NUTContext),
|
---|
1442 | #ifdef CONFIG_LIBVORBIS
|
---|
1443 | CODEC_ID_VORBIS,
|
---|
1444 | #elif defined(CONFIG_MP3LAME)
|
---|
1445 | CODEC_ID_MP3,
|
---|
1446 | #else
|
---|
1447 | CODEC_ID_MP2, /* AC3 needs liba52 decoder */
|
---|
1448 | #endif
|
---|
1449 | CODEC_ID_MPEG4,
|
---|
1450 | nut_write_header,
|
---|
1451 | nut_write_packet,
|
---|
1452 | nut_write_trailer,
|
---|
1453 | .flags = AVFMT_GLOBALHEADER,
|
---|
1454 | };
|
---|
1455 | #endif //CONFIG_MUXERS
|
---|
1456 |
|
---|
1457 | int nut_init(void)
|
---|
1458 | {
|
---|
1459 | av_register_input_format(&nut_demuxer);
|
---|
1460 | #ifdef CONFIG_MUXERS
|
---|
1461 | av_register_output_format(&nut_muxer);
|
---|
1462 | #endif //CONFIG_MUXERS
|
---|
1463 | return 0;
|
---|
1464 | }
|
---|