00001 /* 00002 * NUT (de)muxing via libnut 00003 * copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org> 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00028 #include "avformat.h" 00029 #include "internal.h" 00030 #include "riff.h" 00031 #include <libnut.h> 00032 00033 #define ID_STRING "nut/multimedia container" 00034 #define ID_LENGTH (strlen(ID_STRING) + 1) 00035 00036 typedef struct { 00037 nut_context_tt * nut; 00038 nut_stream_header_tt * s; 00039 } NUTContext; 00040 00041 static const AVCodecTag nut_tags[] = { 00042 { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, 00043 { CODEC_ID_MP3, MKTAG('m', 'p', '3', ' ') }, 00044 { CODEC_ID_VORBIS, MKTAG('v', 'r', 'b', 's') }, 00045 { 0, 0 }, 00046 }; 00047 00048 #if CONFIG_LIBNUT_MUXER 00049 static int av_write(void * h, size_t len, const uint8_t * buf) { 00050 AVIOContext * bc = h; 00051 avio_write(bc, buf, len); 00052 //avio_flush(bc); 00053 return len; 00054 } 00055 00056 static int nut_write_header(AVFormatContext * avf) { 00057 NUTContext * priv = avf->priv_data; 00058 AVIOContext * bc = avf->pb; 00059 nut_muxer_opts_tt mopts = { 00060 .output = { 00061 .priv = bc, 00062 .write = av_write, 00063 }, 00064 .alloc = { av_malloc, av_realloc, av_free }, 00065 .write_index = 1, 00066 .realtime_stream = 0, 00067 .max_distance = 32768, 00068 .fti = NULL, 00069 }; 00070 nut_stream_header_tt * s; 00071 int i; 00072 00073 priv->s = s = av_mallocz((avf->nb_streams + 1) * sizeof*s); 00074 if(!s) 00075 return AVERROR(ENOMEM); 00076 00077 for (i = 0; i < avf->nb_streams; i++) { 00078 AVCodecContext * codec = avf->streams[i]->codec; 00079 int j; 00080 int fourcc = 0; 00081 int num, denom, ssize; 00082 00083 s[i].type = codec->codec_type == AVMEDIA_TYPE_VIDEO ? NUT_VIDEO_CLASS : NUT_AUDIO_CLASS; 00084 00085 if (codec->codec_tag) fourcc = codec->codec_tag; 00086 else fourcc = ff_codec_get_tag(nut_tags, codec->codec_id); 00087 00088 if (!fourcc) { 00089 if (codec->codec_type == AVMEDIA_TYPE_VIDEO) fourcc = ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id); 00090 if (codec->codec_type == AVMEDIA_TYPE_AUDIO) fourcc = ff_codec_get_tag(ff_codec_wav_tags, codec->codec_id); 00091 } 00092 00093 s[i].fourcc_len = 4; 00094 s[i].fourcc = av_malloc(s[i].fourcc_len); 00095 for (j = 0; j < s[i].fourcc_len; j++) s[i].fourcc[j] = (fourcc >> (j*8)) & 0xFF; 00096 00097 ff_parse_specific_params(codec, &num, &ssize, &denom); 00098 avpriv_set_pts_info(avf->streams[i], 60, denom, num); 00099 00100 s[i].time_base.num = denom; 00101 s[i].time_base.den = num; 00102 00103 s[i].fixed_fps = 0; 00104 s[i].decode_delay = codec->has_b_frames; 00105 s[i].codec_specific_len = codec->extradata_size; 00106 s[i].codec_specific = codec->extradata; 00107 00108 if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { 00109 s[i].width = codec->width; 00110 s[i].height = codec->height; 00111 s[i].sample_width = 0; 00112 s[i].sample_height = 0; 00113 s[i].colorspace_type = 0; 00114 } else { 00115 s[i].samplerate_num = codec->sample_rate; 00116 s[i].samplerate_denom = 1; 00117 s[i].channel_count = codec->channels; 00118 } 00119 } 00120 00121 s[avf->nb_streams].type = -1; 00122 priv->nut = nut_muxer_init(&mopts, s, NULL); 00123 00124 return 0; 00125 } 00126 00127 static int nut_write_packet(AVFormatContext * avf, AVPacket * pkt) { 00128 NUTContext * priv = avf->priv_data; 00129 nut_packet_tt p; 00130 00131 p.len = pkt->size; 00132 p.stream = pkt->stream_index; 00133 p.pts = pkt->pts; 00134 p.flags = pkt->flags & AV_PKT_FLAG_KEY ? NUT_FLAG_KEY : 0; 00135 p.next_pts = 0; 00136 00137 nut_write_frame_reorder(priv->nut, &p, pkt->data); 00138 00139 return 0; 00140 } 00141 00142 static int nut_write_trailer(AVFormatContext * avf) { 00143 AVIOContext * bc = avf->pb; 00144 NUTContext * priv = avf->priv_data; 00145 int i; 00146 00147 nut_muxer_uninit_reorder(priv->nut); 00148 avio_flush(bc); 00149 00150 for(i = 0; priv->s[i].type != -1; i++ ) av_freep(&priv->s[i].fourcc); 00151 av_freep(&priv->s); 00152 00153 return 0; 00154 } 00155 00156 AVOutputFormat ff_libnut_muxer = { 00157 .name = "libnut", 00158 .long_name = "nut format", 00159 .mime_type = "video/x-nut", 00160 .extensions = "nut", 00161 .priv_data_size = sizeof(NUTContext), 00162 .audio_codec = CODEC_ID_VORBIS, 00163 .video_codec = CODEC_ID_MPEG4, 00164 .write_header = nut_write_header, 00165 .write_packet = nut_write_packet, 00166 .write_trailer = nut_write_trailer, 00167 .flags = AVFMT_GLOBALHEADER, 00168 }; 00169 #endif /* CONFIG_LIBNUT_MUXER */ 00170 00171 static int nut_probe(AVProbeData *p) { 00172 if (!memcmp(p->buf, ID_STRING, ID_LENGTH)) return AVPROBE_SCORE_MAX; 00173 00174 return 0; 00175 } 00176 00177 static size_t av_read(void * h, size_t len, uint8_t * buf) { 00178 AVIOContext * bc = h; 00179 return avio_read(bc, buf, len); 00180 } 00181 00182 static off_t av_seek(void * h, long long pos, int whence) { 00183 AVIOContext * bc = h; 00184 if (whence == SEEK_END) { 00185 pos = avio_size(bc) + pos; 00186 whence = SEEK_SET; 00187 } 00188 return avio_seek(bc, pos, whence); 00189 } 00190 00191 static int nut_read_header(AVFormatContext * avf, AVFormatParameters * ap) { 00192 NUTContext * priv = avf->priv_data; 00193 AVIOContext * bc = avf->pb; 00194 nut_demuxer_opts_tt dopts = { 00195 .input = { 00196 .priv = bc, 00197 .seek = av_seek, 00198 .read = av_read, 00199 .eof = NULL, 00200 .file_pos = 0, 00201 }, 00202 .alloc = { av_malloc, av_realloc, av_free }, 00203 .read_index = 1, 00204 .cache_syncpoints = 1, 00205 }; 00206 nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts); 00207 nut_stream_header_tt * s; 00208 int ret, i; 00209 00210 if(!nut) 00211 return -1; 00212 00213 if ((ret = nut_read_headers(nut, &s, NULL))) { 00214 av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret)); 00215 nut_demuxer_uninit(nut); 00216 priv->nut = NULL; 00217 return -1; 00218 } 00219 00220 priv->s = s; 00221 00222 for (i = 0; s[i].type != -1 && i < 2; i++) { 00223 AVStream * st = avformat_new_stream(avf, NULL); 00224 int j; 00225 00226 for (j = 0; j < s[i].fourcc_len && j < 8; j++) st->codec->codec_tag |= s[i].fourcc[j]<<(j*8); 00227 00228 st->codec->has_b_frames = s[i].decode_delay; 00229 00230 st->codec->extradata_size = s[i].codec_specific_len; 00231 if (st->codec->extradata_size) { 00232 st->codec->extradata = av_mallocz(st->codec->extradata_size); 00233 if(!st->codec->extradata){ 00234 nut_demuxer_uninit(nut); 00235 priv->nut = NULL; 00236 return AVERROR(ENOMEM); 00237 } 00238 memcpy(st->codec->extradata, s[i].codec_specific, st->codec->extradata_size); 00239 } 00240 00241 avpriv_set_pts_info(avf->streams[i], 60, s[i].time_base.num, s[i].time_base.den); 00242 st->start_time = 0; 00243 st->duration = s[i].max_pts; 00244 00245 st->codec->codec_id = ff_codec_get_id(nut_tags, st->codec->codec_tag); 00246 00247 switch(s[i].type) { 00248 case NUT_AUDIO_CLASS: 00249 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00250 if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, st->codec->codec_tag); 00251 00252 st->codec->channels = s[i].channel_count; 00253 st->codec->sample_rate = s[i].samplerate_num / s[i].samplerate_denom; 00254 break; 00255 case NUT_VIDEO_CLASS: 00256 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00257 if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, st->codec->codec_tag); 00258 00259 st->codec->width = s[i].width; 00260 st->codec->height = s[i].height; 00261 st->sample_aspect_ratio.num = s[i].sample_width; 00262 st->sample_aspect_ratio.den = s[i].sample_height; 00263 break; 00264 } 00265 if (st->codec->codec_id == CODEC_ID_NONE) av_log(avf, AV_LOG_ERROR, "Unknown codec?!\n"); 00266 } 00267 00268 return 0; 00269 } 00270 00271 static int nut_read_packet(AVFormatContext * avf, AVPacket * pkt) { 00272 NUTContext * priv = avf->priv_data; 00273 nut_packet_tt pd; 00274 int ret; 00275 00276 ret = nut_read_next_packet(priv->nut, &pd); 00277 00278 if (ret || av_new_packet(pkt, pd.len) < 0) { 00279 if (ret != NUT_ERR_EOF) 00280 av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret)); 00281 return -1; 00282 } 00283 00284 if (pd.flags & NUT_FLAG_KEY) pkt->flags |= AV_PKT_FLAG_KEY; 00285 pkt->pts = pd.pts; 00286 pkt->stream_index = pd.stream; 00287 pkt->pos = avio_tell(avf->pb); 00288 00289 ret = nut_read_frame(priv->nut, &pd.len, pkt->data); 00290 00291 return ret; 00292 } 00293 00294 static int nut_read_seek(AVFormatContext * avf, int stream_index, int64_t target_ts, int flags) { 00295 NUTContext * priv = avf->priv_data; 00296 int active_streams[] = { stream_index, -1 }; 00297 double time_pos = target_ts * priv->s[stream_index].time_base.num / (double)priv->s[stream_index].time_base.den; 00298 00299 if (nut_seek(priv->nut, time_pos, 2*!(flags & AVSEEK_FLAG_BACKWARD), active_streams)) return -1; 00300 00301 return 0; 00302 } 00303 00304 static int nut_read_close(AVFormatContext *s) { 00305 NUTContext * priv = s->priv_data; 00306 00307 nut_demuxer_uninit(priv->nut); 00308 00309 return 0; 00310 } 00311 00312 AVInputFormat ff_libnut_demuxer = { 00313 .name = "libnut", 00314 .long_name = NULL_IF_CONFIG_SMALL("NUT format"), 00315 .priv_data_size = sizeof(NUTContext), 00316 .read_probe = nut_probe, 00317 .read_header = nut_read_header, 00318 .read_packet = nut_read_packet, 00319 .read_close = nut_read_close, 00320 .read_seek = nut_read_seek, 00321 .extensions = "nut", 00322 };