comparison nutenc.c @ 2324:919efc8760a0 libavformat

trying to finally get the nut muxer back uptodate this one only writes the framecode table and mainheader though they should be compliant to the current spec
author michael
date Thu, 09 Aug 2007 01:12:48 +0000
parents
children 2829faf72879
comparison
equal deleted inserted replaced
2323:43b803972ffd 2324:919efc8760a0
1 /*
2 * nut muxer
3 * Copyright (c) 2004-2007 Michael Niedermayer
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "nut.h"
23
24 #define TRACE
25
26 static void build_frame_code(AVFormatContext *s){
27 NUTContext *nut = s->priv_data;
28 int key_frame, index, pred, stream_id;
29 int start=1;
30 int end= 254;
31 int keyframe_0_esc= s->nb_streams > 2;
32 int pred_table[10];
33
34 if(keyframe_0_esc){
35 /* keyframe = 0 escape */
36 FrameCode *ft= &nut->frame_code[start];
37 ft->flags= FLAG_STREAM_ID | FLAG_SIZE_MSB | FLAG_CODED_PTS;
38 ft->size_mul=1;
39 start++;
40 }
41
42 for(stream_id= 0; stream_id<s->nb_streams; stream_id++){
43 int start2= start + (end-start)*stream_id / s->nb_streams;
44 int end2 = start + (end-start)*(stream_id+1) / s->nb_streams;
45 AVCodecContext *codec = s->streams[stream_id]->codec;
46 int is_audio= codec->codec_type == CODEC_TYPE_AUDIO;
47 int intra_only= /*codec->intra_only || */is_audio;
48 int pred_count;
49
50 for(key_frame=0; key_frame<2; key_frame++){
51 if(intra_only && keyframe_0_esc && key_frame==0)
52 continue;
53
54 {
55 FrameCode *ft= &nut->frame_code[start2];
56 ft->flags= FLAG_KEY*key_frame;
57 ft->flags|= FLAG_SIZE_MSB | FLAG_CODED_PTS;
58 ft->stream_id= stream_id;
59 ft->size_mul=1;
60 start2++;
61 }
62 }
63
64 key_frame= intra_only;
65 #if 1
66 if(is_audio){
67 int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate);
68 int pts;
69 for(pts=0; pts<2; pts++){
70 for(pred=0; pred<2; pred++){
71 FrameCode *ft= &nut->frame_code[start2];
72 ft->flags= FLAG_KEY*key_frame;
73 ft->stream_id= stream_id;
74 ft->size_mul=frame_bytes + 2;
75 ft->size_lsb=frame_bytes + pred;
76 ft->pts_delta=pts;
77 start2++;
78 }
79 }
80 }else{
81 FrameCode *ft= &nut->frame_code[start2];
82 ft->flags= FLAG_KEY | FLAG_SIZE_MSB;
83 ft->stream_id= stream_id;
84 ft->size_mul=1;
85 ft->pts_delta=1;
86 start2++;
87 }
88 #endif
89
90 if(codec->has_b_frames){
91 pred_count=5;
92 pred_table[0]=-2;
93 pred_table[1]=-1;
94 pred_table[2]=1;
95 pred_table[3]=3;
96 pred_table[4]=4;
97 }else if(codec->codec_id == CODEC_ID_VORBIS){
98 pred_count=3;
99 pred_table[0]=2;
100 pred_table[1]=9;
101 pred_table[2]=16;
102 }else{
103 pred_count=1;
104 pred_table[0]=1;
105 }
106
107 for(pred=0; pred<pred_count; pred++){
108 int start3= start2 + (end2-start2)*pred / pred_count;
109 int end3 = start2 + (end2-start2)*(pred+1) / pred_count;
110
111 for(index=start3; index<end3; index++){
112 FrameCode *ft= &nut->frame_code[index];
113 ft->flags= FLAG_KEY*key_frame;
114 ft->flags|= FLAG_SIZE_MSB;
115 ft->stream_id= stream_id;
116 //FIXME use single byte size and pred from last
117 ft->size_mul= end3-start3;
118 ft->size_lsb= index - start3;
119 ft->pts_delta= pred_table[pred];
120 }
121 }
122 }
123 memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N'));
124 nut->frame_code[ 0].flags=
125 nut->frame_code[255].flags=
126 nut->frame_code['N'].flags= FLAG_INVALID;
127 }
128
129 /**
130 * Gets the length in bytes which is needed to store val as v.
131 */
132 static int get_length(uint64_t val){
133 int i=1;
134
135 while(val>>=7)
136 i++;
137
138 return i;
139 }
140
141 static void put_v(ByteIOContext *bc, uint64_t val){
142 int i= get_length(val);
143
144 while(--i>0)
145 put_byte(bc, 128 | (val>>(7*i)));
146
147 put_byte(bc, val&127);
148 }
149
150 /**
151 * stores a string as vb.
152 */
153 static void put_str(ByteIOContext *bc, const char *string){
154 int len= strlen(string);
155
156 put_v(bc, len);
157 put_buffer(bc, string, len);
158 }
159
160 static void put_s(ByteIOContext *bc, int64_t val){
161 put_v(bc, 2*FFABS(val) - (val>0));
162 }
163
164 #ifdef TRACE
165 static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
166 printf("get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
167
168 put_v(bc, v);
169 }
170
171 static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){
172 printf("get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
173
174 put_s(bc, v);
175 }
176 #define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
177 #define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
178 #endif
179
180 static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum){
181 put_flush_packet(bc);
182 nut->packet_start= url_ftell(bc) - 8;
183 nut->written_packet_size = max_size;
184
185 /* packet header */
186 put_v(bc, nut->written_packet_size); /* forward ptr */
187
188 if(calculate_checksum)
189 init_checksum(bc, av_crc04C11DB7_update, 0);
190
191 return 0;
192 }
193
194 /**
195 *
196 * must not be called more then once per packet
197 */
198 static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){
199 int64_t start= nut->packet_start;
200 int64_t cur= url_ftell(bc);
201 int size= cur - start - get_length(nut->written_packet_size) - 8;
202
203 if(calculate_checksum)
204 size += 4;
205
206 if(size != nut->written_packet_size){
207 int i;
208
209 assert( size <= nut->written_packet_size );
210
211 url_fseek(bc, start + 8, SEEK_SET);
212 for(i=get_length(size); i < get_length(nut->written_packet_size); i++)
213 put_byte(bc, 128);
214 put_v(bc, size);
215
216 url_fseek(bc, cur, SEEK_SET);
217 nut->written_packet_size= size; //FIXME may fail if multiple updates with differing sizes, as get_length may differ
218
219 if(calculate_checksum)
220 put_le32(bc, get_checksum(bc));
221 }
222
223 return 0;
224 }
225
226 static int write_header(AVFormatContext *s){
227 NUTContext *nut = s->priv_data;
228 ByteIOContext *bc = &s->pb;
229 AVCodecContext *codec;
230 int i, j, tmp_pts, tmp_flags, tmp_stream, tmp_mul, tmp_size, tmp_fields;
231
232 nut->avf= s;
233
234 nut->stream = av_mallocz(sizeof(StreamContext)*s->nb_streams);
235 nut->time_base= av_mallocz(sizeof(AVRational )*s->nb_streams);
236
237 for(i=0; i<s->nb_streams; i++){
238 AVStream *st= s->streams[i];
239 int num, denom, ssize;
240 ff_parse_specific_params(st->codec, &num, &ssize, &denom);
241
242 nut->stream[i].time_base= (AVRational){denom, num};
243
244 av_set_pts_info(st, 64, denom, num);
245
246 for(j=0; j<nut->time_base_count; j++){
247 if(!memcmp(&nut->stream[i].time_base, &nut->time_base[j], sizeof(AVRational))){
248 break;
249 }
250 }
251 nut->time_base[j]= nut->stream[i].time_base;
252 if(j==nut->time_base_count)
253 nut->time_base_count++;
254 }
255 //FIXME make nut->stream[i].time_base pointers into nut->time_base
256
257 put_buffer(bc, ID_STRING, strlen(ID_STRING));
258 put_byte(bc, 0);
259
260 /* main header */
261 put_be64(bc, MAIN_STARTCODE);
262 put_packetheader(nut, bc, 120+5*256/*FIXME check*/, 1);
263
264 put_v(bc, 2); /* version */
265 put_v(bc, s->nb_streams);
266 put_v(bc, MAX_DISTANCE);
267 put_v(bc, nut->time_base_count);
268
269 for(i=0; i<nut->time_base_count; i++){
270 put_v(bc, nut->time_base[i].num);
271 put_v(bc, nut->time_base[i].den);
272 }
273
274 build_frame_code(s);
275 assert(nut->frame_code['N'].flags == FLAG_INVALID);
276
277 tmp_pts=0;
278 tmp_mul=1;
279 tmp_stream=0;
280 for(i=0; i<256;){
281 tmp_fields=0;
282 tmp_size=0;
283 // tmp_res=0;
284 if(tmp_pts != nut->frame_code[i].pts_delta) tmp_fields=1;
285 if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2;
286 if(tmp_stream != nut->frame_code[i].stream_id) tmp_fields=3;
287 if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4;
288 // if(tmp_res != nut->frame_code[i].res ) tmp_fields=5;
289
290 tmp_pts = nut->frame_code[i].pts_delta;
291 tmp_flags = nut->frame_code[i].flags;
292 tmp_stream= nut->frame_code[i].stream_id;
293 tmp_mul = nut->frame_code[i].size_mul;
294 tmp_size = nut->frame_code[i].size_lsb;
295 // tmp_res = nut->frame_code[i].res;
296
297 for(j=0; i<256; j++,i++){
298 if(i == 'N'){
299 j--;
300 continue;
301 }
302 if(nut->frame_code[i].pts_delta != tmp_pts ) break;
303 if(nut->frame_code[i].flags != tmp_flags ) break;
304 if(nut->frame_code[i].stream_id != tmp_stream) break;
305 if(nut->frame_code[i].size_mul != tmp_mul ) break;
306 if(nut->frame_code[i].size_lsb != tmp_size+j) break;
307 // if(nut->frame_code[i].res != tmp_res ) break;
308 }
309 if(j != tmp_mul - tmp_size) tmp_fields=6;
310
311 put_v(bc, tmp_flags);
312 put_v(bc, tmp_fields);
313 if(tmp_fields>0) put_s(bc, tmp_pts);
314 if(tmp_fields>1) put_v(bc, tmp_mul);
315 if(tmp_fields>2) put_v(bc, tmp_stream);
316 if(tmp_fields>3) put_v(bc, tmp_size);
317 if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/);
318 if(tmp_fields>5) put_v(bc, j);
319 }
320
321 update_packetheader(nut, bc, 0, 1);
322
323 put_flush_packet(bc);
324
325 //FIXME stream header, ...
326
327 return 0;
328 }
329
330 static int write_packet(AVFormatContext *s, AVPacket *pkt){
331 //FIXME
332 return 0;
333 }
334
335 AVOutputFormat nut_muxer = {
336 "nut",
337 "nut format",
338 "video/x-nut",
339 "nut",
340 sizeof(NUTContext),
341 #ifdef CONFIG_LIBVORBIS
342 CODEC_ID_VORBIS,
343 #elif defined(CONFIG_LIBMP3LAME)
344 CODEC_ID_MP3,
345 #else
346 CODEC_ID_MP2, /* AC3 needs liba52 decoder */
347 #endif
348 CODEC_ID_MPEG4,
349 write_header,
350 write_packet,
351 // write_trailer,
352 .flags = AVFMT_GLOBALHEADER,
353 };