1/* 2 * NUT (de)muxing via libnut 3 * copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org> 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * NUT demuxing and muxing via libnut. 25 * @author Oded Shimon <ods15@ods15.dyndns.org> 26 */ 27 28#include "avformat.h" 29#include "internal.h" 30#include "riff.h" 31#include <libnut.h> 32 33#define ID_STRING "nut/multimedia container" 34#define ID_LENGTH (strlen(ID_STRING) + 1) 35 36typedef struct { 37 nut_context_tt * nut; 38 nut_stream_header_tt * s; 39} NUTContext; 40 41static const AVCodecTag nut_tags[] = { 42 { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, 43 { CODEC_ID_MP3, MKTAG('m', 'p', '3', ' ') }, 44 { CODEC_ID_VORBIS, MKTAG('v', 'r', 'b', 's') }, 45 { 0, 0 }, 46}; 47 48#if CONFIG_LIBNUT_MUXER 49static int av_write(void * h, size_t len, const uint8_t * buf) { 50 AVIOContext * bc = h; 51 avio_write(bc, buf, len); 52 //avio_flush(bc); 53 return len; 54} 55 56static int nut_write_header(AVFormatContext * avf) { 57 NUTContext * priv = avf->priv_data; 58 AVIOContext * bc = avf->pb; 59 nut_muxer_opts_tt mopts = { 60 .output = { 61 .priv = bc, 62 .write = av_write, 63 }, 64 .alloc = { av_malloc, av_realloc, av_free }, 65 .write_index = 1, 66 .realtime_stream = 0, 67 .max_distance = 32768, 68 .fti = NULL, 69 }; 70 nut_stream_header_tt * s; 71 int i; 72 73 priv->s = s = av_mallocz((avf->nb_streams + 1) * sizeof*s); 74 75 for (i = 0; i < avf->nb_streams; i++) { 76 AVCodecContext * codec = avf->streams[i]->codec; 77 int j; 78 int fourcc = 0; 79 int num, denom, ssize; 80 81 s[i].type = codec->codec_type == AVMEDIA_TYPE_VIDEO ? NUT_VIDEO_CLASS : NUT_AUDIO_CLASS; 82 83 if (codec->codec_tag) fourcc = codec->codec_tag; 84 else fourcc = ff_codec_get_tag(nut_tags, codec->codec_id); 85 86 if (!fourcc) { 87 if (codec->codec_type == AVMEDIA_TYPE_VIDEO) fourcc = ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id); 88 if (codec->codec_type == AVMEDIA_TYPE_AUDIO) fourcc = ff_codec_get_tag(ff_codec_wav_tags, codec->codec_id); 89 } 90 91 s[i].fourcc_len = 4; 92 s[i].fourcc = av_malloc(s[i].fourcc_len); 93 for (j = 0; j < s[i].fourcc_len; j++) s[i].fourcc[j] = (fourcc >> (j*8)) & 0xFF; 94 95 ff_parse_specific_params(codec, &num, &ssize, &denom); 96 avpriv_set_pts_info(avf->streams[i], 60, denom, num); 97 98 s[i].time_base.num = denom; 99 s[i].time_base.den = num; 100 101 s[i].fixed_fps = 0; 102 s[i].decode_delay = codec->has_b_frames; 103 s[i].codec_specific_len = codec->extradata_size; 104 s[i].codec_specific = codec->extradata; 105 106 if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { 107 s[i].width = codec->width; 108 s[i].height = codec->height; 109 s[i].sample_width = 0; 110 s[i].sample_height = 0; 111 s[i].colorspace_type = 0; 112 } else { 113 s[i].samplerate_num = codec->sample_rate; 114 s[i].samplerate_denom = 1; 115 s[i].channel_count = codec->channels; 116 } 117 } 118 119 s[avf->nb_streams].type = -1; 120 priv->nut = nut_muxer_init(&mopts, s, NULL); 121 122 return 0; 123} 124 125static int nut_write_packet(AVFormatContext * avf, AVPacket * pkt) { 126 NUTContext * priv = avf->priv_data; 127 nut_packet_tt p; 128 129 p.len = pkt->size; 130 p.stream = pkt->stream_index; 131 p.pts = pkt->pts; 132 p.flags = pkt->flags & AV_PKT_FLAG_KEY ? NUT_FLAG_KEY : 0; 133 p.next_pts = 0; 134 135 nut_write_frame_reorder(priv->nut, &p, pkt->data); 136 137 return 0; 138} 139 140static int nut_write_trailer(AVFormatContext * avf) { 141 AVIOContext * bc = avf->pb; 142 NUTContext * priv = avf->priv_data; 143 int i; 144 145 nut_muxer_uninit_reorder(priv->nut); 146 avio_flush(bc); 147 148 for(i = 0; priv->s[i].type != -1; i++ ) av_freep(&priv->s[i].fourcc); 149 av_freep(&priv->s); 150 151 return 0; 152} 153 154AVOutputFormat ff_libnut_muxer = { 155 .name = "libnut", 156 .long_name = "nut format", 157 .mime_type = "video/x-nut", 158 .extensions = "nut", 159 .priv_data_size = sizeof(NUTContext), 160 .audio_codec = CODEC_ID_VORBIS, 161 .video_codec = CODEC_ID_MPEG4, 162 .write_header = nut_write_header, 163 .write_packet = nut_write_packet, 164 .write_trailer = nut_write_trailer, 165 .flags = AVFMT_GLOBALHEADER, 166}; 167#endif /* CONFIG_LIBNUT_MUXER */ 168 169static int nut_probe(AVProbeData *p) { 170 if (!memcmp(p->buf, ID_STRING, ID_LENGTH)) return AVPROBE_SCORE_MAX; 171 172 return 0; 173} 174 175static size_t av_read(void * h, size_t len, uint8_t * buf) { 176 AVIOContext * bc = h; 177 return avio_read(bc, buf, len); 178} 179 180static off_t av_seek(void * h, long long pos, int whence) { 181 AVIOContext * bc = h; 182 if (whence == SEEK_END) { 183 pos = avio_size(bc) + pos; 184 whence = SEEK_SET; 185 } 186 return avio_seek(bc, pos, whence); 187} 188 189static int nut_read_header(AVFormatContext * avf, AVFormatParameters * ap) { 190 NUTContext * priv = avf->priv_data; 191 AVIOContext * bc = avf->pb; 192 nut_demuxer_opts_tt dopts = { 193 .input = { 194 .priv = bc, 195 .seek = av_seek, 196 .read = av_read, 197 .eof = NULL, 198 .file_pos = 0, 199 }, 200 .alloc = { av_malloc, av_realloc, av_free }, 201 .read_index = 1, 202 .cache_syncpoints = 1, 203 }; 204 nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts); 205 nut_stream_header_tt * s; 206 int ret, i; 207 208 if ((ret = nut_read_headers(nut, &s, NULL))) { 209 av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret)); 210 nut_demuxer_uninit(nut); 211 return -1; 212 } 213 214 priv->s = s; 215 216 for (i = 0; s[i].type != -1 && i < 2; i++) { 217 AVStream * st = avformat_new_stream(avf, NULL); 218 int j; 219 220 for (j = 0; j < s[i].fourcc_len && j < 8; j++) st->codec->codec_tag |= s[i].fourcc[j]<<(j*8); 221 222 st->codec->has_b_frames = s[i].decode_delay; 223 224 st->codec->extradata_size = s[i].codec_specific_len; 225 if (st->codec->extradata_size) { 226 st->codec->extradata = av_mallocz(st->codec->extradata_size); 227 memcpy(st->codec->extradata, s[i].codec_specific, st->codec->extradata_size); 228 } 229 230 avpriv_set_pts_info(avf->streams[i], 60, s[i].time_base.num, s[i].time_base.den); 231 st->start_time = 0; 232 st->duration = s[i].max_pts; 233 234 st->codec->codec_id = ff_codec_get_id(nut_tags, st->codec->codec_tag); 235 236 switch(s[i].type) { 237 case NUT_AUDIO_CLASS: 238 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 239 if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, st->codec->codec_tag); 240 241 st->codec->channels = s[i].channel_count; 242 st->codec->sample_rate = s[i].samplerate_num / s[i].samplerate_denom; 243 break; 244 case NUT_VIDEO_CLASS: 245 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 246 if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, st->codec->codec_tag); 247 248 st->codec->width = s[i].width; 249 st->codec->height = s[i].height; 250 st->sample_aspect_ratio.num = s[i].sample_width; 251 st->sample_aspect_ratio.den = s[i].sample_height; 252 break; 253 } 254 if (st->codec->codec_id == CODEC_ID_NONE) av_log(avf, AV_LOG_ERROR, "Unknown codec?!\n"); 255 } 256 257 return 0; 258} 259 260static int nut_read_packet(AVFormatContext * avf, AVPacket * pkt) { 261 NUTContext * priv = avf->priv_data; 262 nut_packet_tt pd; 263 int ret; 264 265 ret = nut_read_next_packet(priv->nut, &pd); 266 267 if (ret || av_new_packet(pkt, pd.len) < 0) { 268 if (ret != NUT_ERR_EOF) 269 av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret)); 270 return -1; 271 } 272 273 if (pd.flags & NUT_FLAG_KEY) pkt->flags |= AV_PKT_FLAG_KEY; 274 pkt->pts = pd.pts; 275 pkt->stream_index = pd.stream; 276 pkt->pos = avio_tell(avf->pb); 277 278 ret = nut_read_frame(priv->nut, &pd.len, pkt->data); 279 280 return ret; 281} 282 283static int nut_read_seek(AVFormatContext * avf, int stream_index, int64_t target_ts, int flags) { 284 NUTContext * priv = avf->priv_data; 285 int active_streams[] = { stream_index, -1 }; 286 double time_pos = target_ts * priv->s[stream_index].time_base.num / (double)priv->s[stream_index].time_base.den; 287 288 if (nut_seek(priv->nut, time_pos, 2*!(flags & AVSEEK_FLAG_BACKWARD), active_streams)) return -1; 289 290 return 0; 291} 292 293static int nut_read_close(AVFormatContext *s) { 294 NUTContext * priv = s->priv_data; 295 296 nut_demuxer_uninit(priv->nut); 297 298 return 0; 299} 300 301AVInputFormat ff_libnut_demuxer = { 302 .name = "libnut", 303 .long_name = NULL_IF_CONFIG_SMALL("NUT format"), 304 .priv_data_size = sizeof(NUTContext), 305 .read_probe = nut_probe, 306 .read_header = nut_read_header, 307 .read_packet = nut_read_packet, 308 .read_close = nut_read_close, 309 .read_seek = nut_read_seek, 310 .extensions = "nut", 311}; 312