2 * NUT (de)muxing via libnut
3 * copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
5 * This file is part of FFmpeg.
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.
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.
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
24 * NUT demuxing and muxing via libnut.
25 * @author Oded Shimon <ods15@ods15.dyndns.org>
33 #define ID_STRING "nut/multimedia container"
34 #define ID_LENGTH (strlen(ID_STRING) + 1)
38 nut_stream_header_tt
* s
;
41 static const AVCodecTag nut_tags
[] = {
42 { AV_CODEC_ID_MPEG4
, MKTAG('m', 'p', '4', 'v') },
43 { AV_CODEC_ID_MP3
, MKTAG('m', 'p', '3', ' ') },
44 { AV_CODEC_ID_VORBIS
, MKTAG('v', 'r', 'b', 's') },
48 #if CONFIG_LIBNUT_MUXER
49 static int av_write(void * h
, size_t len
, const uint8_t * buf
) {
51 avio_write(bc
, buf
, len
);
56 static int nut_write_header(AVFormatContext
* avf
) {
57 NUTContext
* priv
= avf
->priv_data
;
58 AVIOContext
* bc
= avf
->pb
;
59 nut_muxer_opts_tt mopts
= {
64 .alloc
= { av_malloc
, av_realloc
, av_free
},
67 .max_distance
= 32768,
70 nut_stream_header_tt
* s
;
73 priv
->s
= s
= av_mallocz_array(avf
->nb_streams
+ 1, sizeof*s
);
75 return AVERROR(ENOMEM
);
77 for (i
= 0; i
< avf
->nb_streams
; i
++) {
78 AVCodecContext
* codec
= avf
->streams
[i
]->codec
;
81 int num
, denom
, ssize
;
83 s
[i
].type
= codec
->codec_type
== AVMEDIA_TYPE_VIDEO
? NUT_VIDEO_CLASS
: NUT_AUDIO_CLASS
;
85 if (codec
->codec_tag
) fourcc
= codec
->codec_tag
;
86 else fourcc
= ff_codec_get_tag(nut_tags
, codec
->codec_id
);
89 if (codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) fourcc
= ff_codec_get_tag(ff_codec_bmp_tags
, codec
->codec_id
);
90 if (codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) fourcc
= ff_codec_get_tag(ff_codec_wav_tags
, codec
->codec_id
);
94 s
[i
].fourcc
= av_malloc(s
[i
].fourcc_len
);
95 for (j
= 0; j
< s
[i
].fourcc_len
; j
++) s
[i
].fourcc
[j
] = (fourcc
>> (j
*8)) & 0xFF;
97 ff_parse_specific_params(codec
, &num
, &ssize
, &denom
);
98 avpriv_set_pts_info(avf
->streams
[i
], 60, denom
, num
);
100 s
[i
].time_base
.num
= denom
;
101 s
[i
].time_base
.den
= num
;
104 s
[i
].decode_delay
= codec
->has_b_frames
;
105 s
[i
].codec_specific_len
= codec
->extradata_size
;
106 s
[i
].codec_specific
= codec
->extradata
;
108 if (codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
109 s
[i
].width
= codec
->width
;
110 s
[i
].height
= codec
->height
;
111 s
[i
].sample_width
= 0;
112 s
[i
].sample_height
= 0;
113 s
[i
].colorspace_type
= 0;
115 s
[i
].samplerate_num
= codec
->sample_rate
;
116 s
[i
].samplerate_denom
= 1;
117 s
[i
].channel_count
= codec
->channels
;
121 s
[avf
->nb_streams
].type
= -1;
122 priv
->nut
= nut_muxer_init(&mopts
, s
, NULL
);
127 static int nut_write_packet(AVFormatContext
* avf
, AVPacket
* pkt
) {
128 NUTContext
* priv
= avf
->priv_data
;
132 p
.stream
= pkt
->stream_index
;
134 p
.flags
= pkt
->flags
& AV_PKT_FLAG_KEY
? NUT_FLAG_KEY
: 0;
137 nut_write_frame_reorder(priv
->nut
, &p
, pkt
->data
);
142 static int nut_write_trailer(AVFormatContext
* avf
) {
143 AVIOContext
* bc
= avf
->pb
;
144 NUTContext
* priv
= avf
->priv_data
;
147 nut_muxer_uninit_reorder(priv
->nut
);
150 for(i
= 0; priv
->s
[i
].type
!= -1; i
++ ) av_freep(&priv
->s
[i
].fourcc
);
156 AVOutputFormat ff_libnut_muxer
= {
158 .long_name
= "nut format",
159 .mime_type
= "video/x-nut",
161 .priv_data_size
= sizeof(NUTContext
),
162 .audio_codec
= AV_CODEC_ID_VORBIS
,
163 .video_codec
= AV_CODEC_ID_MPEG4
,
164 .write_header
= nut_write_header
,
165 .write_packet
= nut_write_packet
,
166 .write_trailer
= nut_write_trailer
,
167 .flags
= AVFMT_GLOBALHEADER
,
169 #endif /* CONFIG_LIBNUT_MUXER */
171 static int nut_probe(AVProbeData
*p
) {
172 if (!memcmp(p
->buf
, ID_STRING
, ID_LENGTH
)) return AVPROBE_SCORE_MAX
;
177 static size_t av_read(void * h
, size_t len
, uint8_t * buf
) {
178 AVIOContext
* bc
= h
;
179 return avio_read(bc
, buf
, len
);
182 static off_t
av_seek(void * h
, long long pos
, int whence
) {
183 AVIOContext
* bc
= h
;
184 if (whence
== SEEK_END
) {
185 pos
= avio_size(bc
) + pos
;
188 return avio_seek(bc
, pos
, whence
);
191 static int nut_read_header(AVFormatContext
* avf
) {
192 NUTContext
* priv
= avf
->priv_data
;
193 AVIOContext
* bc
= avf
->pb
;
194 nut_demuxer_opts_tt dopts
= {
202 .alloc
= { av_malloc
, av_realloc
, av_free
},
204 .cache_syncpoints
= 1,
206 nut_context_tt
* nut
= priv
->nut
= nut_demuxer_init(&dopts
);
207 nut_stream_header_tt
* s
;
213 if ((ret
= nut_read_headers(nut
, &s
, NULL
))) {
214 av_log(avf
, AV_LOG_ERROR
, " NUT error: %s\n", nut_error(ret
));
215 nut_demuxer_uninit(nut
);
222 for (i
= 0; s
[i
].type
!= -1 && i
< 2; i
++) {
223 AVStream
* st
= avformat_new_stream(avf
, NULL
);
227 return AVERROR(ENOMEM
);
229 for (j
= 0; j
< s
[i
].fourcc_len
&& j
< 8; j
++) st
->codec
->codec_tag
|= s
[i
].fourcc
[j
]<<(j
*8);
231 st
->codec
->has_b_frames
= s
[i
].decode_delay
;
233 st
->codec
->extradata_size
= s
[i
].codec_specific_len
;
234 if (st
->codec
->extradata_size
) {
235 if(ff_alloc_extradata(st
->codec
, st
->codec
->extradata_size
)){
236 nut_demuxer_uninit(nut
);
238 return AVERROR(ENOMEM
);
240 memcpy(st
->codec
->extradata
, s
[i
].codec_specific
, st
->codec
->extradata_size
);
243 avpriv_set_pts_info(avf
->streams
[i
], 60, s
[i
].time_base
.num
, s
[i
].time_base
.den
);
245 st
->duration
= s
[i
].max_pts
;
247 st
->codec
->codec_id
= ff_codec_get_id(nut_tags
, st
->codec
->codec_tag
);
250 case NUT_AUDIO_CLASS
:
251 st
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
252 if (st
->codec
->codec_id
== AV_CODEC_ID_NONE
) st
->codec
->codec_id
= ff_codec_get_id(ff_codec_wav_tags
, st
->codec
->codec_tag
);
254 st
->codec
->channels
= s
[i
].channel_count
;
255 st
->codec
->sample_rate
= s
[i
].samplerate_num
/ s
[i
].samplerate_denom
;
257 case NUT_VIDEO_CLASS
:
258 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
259 if (st
->codec
->codec_id
== AV_CODEC_ID_NONE
) st
->codec
->codec_id
= ff_codec_get_id(ff_codec_bmp_tags
, st
->codec
->codec_tag
);
261 st
->codec
->width
= s
[i
].width
;
262 st
->codec
->height
= s
[i
].height
;
263 st
->sample_aspect_ratio
.num
= s
[i
].sample_width
;
264 st
->sample_aspect_ratio
.den
= s
[i
].sample_height
;
267 if (st
->codec
->codec_id
== AV_CODEC_ID_NONE
) av_log(avf
, AV_LOG_ERROR
, "Unknown codec?!\n");
273 static int nut_read_packet(AVFormatContext
* avf
, AVPacket
* pkt
) {
274 NUTContext
* priv
= avf
->priv_data
;
278 ret
= nut_read_next_packet(priv
->nut
, &pd
);
280 if (ret
|| av_new_packet(pkt
, pd
.len
) < 0) {
281 if (ret
!= NUT_ERR_EOF
)
282 av_log(avf
, AV_LOG_ERROR
, " NUT error: %s\n", nut_error(ret
));
286 if (pd
.flags
& NUT_FLAG_KEY
) pkt
->flags
|= AV_PKT_FLAG_KEY
;
288 pkt
->stream_index
= pd
.stream
;
289 pkt
->pos
= avio_tell(avf
->pb
);
291 ret
= nut_read_frame(priv
->nut
, &pd
.len
, pkt
->data
);
296 static int nut_read_seek(AVFormatContext
* avf
, int stream_index
, int64_t target_ts
, int flags
) {
297 NUTContext
* priv
= avf
->priv_data
;
298 int active_streams
[] = { stream_index
, -1 };
299 double time_pos
= target_ts
* priv
->s
[stream_index
].time_base
.num
/ (double)priv
->s
[stream_index
].time_base
.den
;
301 if (nut_seek(priv
->nut
, time_pos
, 2*!(flags
& AVSEEK_FLAG_BACKWARD
), active_streams
)) return -1;
306 static int nut_read_close(AVFormatContext
*s
) {
307 NUTContext
* priv
= s
->priv_data
;
309 nut_demuxer_uninit(priv
->nut
);
314 AVInputFormat ff_libnut_demuxer
= {
316 .long_name
= NULL_IF_CONFIG_SMALL("NUT format"),
317 .priv_data_size
= sizeof(NUTContext
),
318 .read_probe
= nut_probe
,
319 .read_header
= nut_read_header
,
320 .read_packet
= nut_read_packet
,
321 .read_close
= nut_read_close
,
322 .read_seek
= nut_read_seek
,