• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/nuv.c

Go to the documentation of this file.
00001 /*
00002  * NuppelVideo demuxer.
00003  * Copyright (c) 2006 Reimar Doeffinger
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 
00022 #include "libavutil/intreadwrite.h"
00023 #include "avformat.h"
00024 #include "riff.h"
00025 
00026 typedef struct {
00027     int v_id;
00028     int a_id;
00029     int rtjpg_video;
00030 } NUVContext;
00031 
00032 typedef enum {
00033     NUV_VIDEO = 'V',
00034     NUV_EXTRADATA = 'D',
00035     NUV_AUDIO = 'A',
00036     NUV_SEEKP = 'R',
00037     NUV_MYTHEXT = 'X'
00038 } nuv_frametype;
00039 
00040 static int nuv_probe(AVProbeData *p) {
00041     if (!memcmp(p->buf, "NuppelVideo", 12))
00042         return AVPROBE_SCORE_MAX;
00043     if (!memcmp(p->buf, "MythTVVideo", 12))
00044         return AVPROBE_SCORE_MAX;
00045     return 0;
00046 }
00047 
00049 #define PKTSIZE(s) (s &  0xffffff)
00050 
00058 static int get_codec_data(ByteIOContext *pb, AVStream *vst,
00059                           AVStream *ast, int myth) {
00060     nuv_frametype frametype;
00061     if (!vst && !myth)
00062         return 1; // no codec data needed
00063     while (!url_feof(pb)) {
00064         int size, subtype;
00065         frametype = get_byte(pb);
00066         switch (frametype) {
00067             case NUV_EXTRADATA:
00068                 subtype = get_byte(pb);
00069                 url_fskip(pb, 6);
00070                 size = PKTSIZE(get_le32(pb));
00071                 if (vst && subtype == 'R') {
00072                     vst->codec->extradata_size = size;
00073                     vst->codec->extradata = av_malloc(size);
00074                     get_buffer(pb, vst->codec->extradata, size);
00075                     size = 0;
00076                     if (!myth)
00077                         return 1;
00078                 }
00079                 break;
00080             case NUV_MYTHEXT:
00081                 url_fskip(pb, 7);
00082                 size = PKTSIZE(get_le32(pb));
00083                 if (size != 128 * 4)
00084                     break;
00085                 get_le32(pb); // version
00086                 if (vst) {
00087                     vst->codec->codec_tag = get_le32(pb);
00088                     vst->codec->codec_id =
00089                         ff_codec_get_id(ff_codec_bmp_tags, vst->codec->codec_tag);
00090                     if (vst->codec->codec_tag == MKTAG('R', 'J', 'P', 'G'))
00091                         vst->codec->codec_id = CODEC_ID_NUV;
00092                 } else
00093                     url_fskip(pb, 4);
00094 
00095                 if (ast) {
00096                     ast->codec->codec_tag = get_le32(pb);
00097                     ast->codec->sample_rate = get_le32(pb);
00098                     ast->codec->bits_per_coded_sample = get_le32(pb);
00099                     ast->codec->channels = get_le32(pb);
00100                     ast->codec->codec_id =
00101                         ff_wav_codec_get_id(ast->codec->codec_tag,
00102                                          ast->codec->bits_per_coded_sample);
00103                     ast->need_parsing = AVSTREAM_PARSE_FULL;
00104                 } else
00105                     url_fskip(pb, 4 * 4);
00106 
00107                 size -= 6 * 4;
00108                 url_fskip(pb, size);
00109                 return 1;
00110             case NUV_SEEKP:
00111                 size = 11;
00112                 break;
00113             default:
00114                 url_fskip(pb, 7);
00115                 size = PKTSIZE(get_le32(pb));
00116                 break;
00117         }
00118         url_fskip(pb, size);
00119     }
00120     return 0;
00121 }
00122 
00123 static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) {
00124     NUVContext *ctx = s->priv_data;
00125     ByteIOContext *pb = s->pb;
00126     char id_string[12];
00127     double aspect, fps;
00128     int is_mythtv, width, height, v_packs, a_packs;
00129     int stream_nr = 0;
00130     AVStream *vst = NULL, *ast = NULL;
00131     get_buffer(pb, id_string, 12);
00132     is_mythtv = !memcmp(id_string, "MythTVVideo", 12);
00133     url_fskip(pb, 5); // version string
00134     url_fskip(pb, 3); // padding
00135     width = get_le32(pb);
00136     height = get_le32(pb);
00137     get_le32(pb); // unused, "desiredwidth"
00138     get_le32(pb); // unused, "desiredheight"
00139     get_byte(pb); // 'P' == progressive, 'I' == interlaced
00140     url_fskip(pb, 3); // padding
00141     aspect = av_int2dbl(get_le64(pb));
00142     if (aspect > 0.9999 && aspect < 1.0001)
00143         aspect = 4.0 / 3.0;
00144     fps = av_int2dbl(get_le64(pb));
00145 
00146     // number of packets per stream type, -1 means unknown, e.g. streaming
00147     v_packs = get_le32(pb);
00148     a_packs = get_le32(pb);
00149     get_le32(pb); // text
00150 
00151     get_le32(pb); // keyframe distance (?)
00152 
00153     if (v_packs) {
00154         ctx->v_id = stream_nr++;
00155         vst = av_new_stream(s, ctx->v_id);
00156         if (!vst)
00157             return AVERROR(ENOMEM);
00158         vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00159         vst->codec->codec_id = CODEC_ID_NUV;
00160         vst->codec->width = width;
00161         vst->codec->height = height;
00162         vst->codec->bits_per_coded_sample = 10;
00163         vst->sample_aspect_ratio = av_d2q(aspect * height / width, 10000);
00164         vst->r_frame_rate = av_d2q(fps, 60000);
00165         av_set_pts_info(vst, 32, 1, 1000);
00166     } else
00167         ctx->v_id = -1;
00168 
00169     if (a_packs) {
00170         ctx->a_id = stream_nr++;
00171         ast = av_new_stream(s, ctx->a_id);
00172         if (!ast)
00173             return AVERROR(ENOMEM);
00174         ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00175         ast->codec->codec_id = CODEC_ID_PCM_S16LE;
00176         ast->codec->channels = 2;
00177         ast->codec->sample_rate = 44100;
00178         ast->codec->bit_rate = 2 * 2 * 44100 * 8;
00179         ast->codec->block_align = 2 * 2;
00180         ast->codec->bits_per_coded_sample = 16;
00181         av_set_pts_info(ast, 32, 1, 1000);
00182     } else
00183         ctx->a_id = -1;
00184 
00185     get_codec_data(pb, vst, ast, is_mythtv);
00186     ctx->rtjpg_video = vst && vst->codec->codec_id == CODEC_ID_NUV;
00187     return 0;
00188 }
00189 
00190 #define HDRSIZE 12
00191 
00192 static int nuv_packet(AVFormatContext *s, AVPacket *pkt) {
00193     NUVContext *ctx = s->priv_data;
00194     ByteIOContext *pb = s->pb;
00195     uint8_t hdr[HDRSIZE];
00196     nuv_frametype frametype;
00197     int ret, size;
00198     while (!url_feof(pb)) {
00199         int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0;
00200         uint64_t pos = url_ftell(pb);
00201         ret = get_buffer(pb, hdr, HDRSIZE);
00202         if (ret < HDRSIZE)
00203             return ret < 0 ? ret : AVERROR(EIO);
00204         frametype = hdr[0];
00205         size = PKTSIZE(AV_RL32(&hdr[8]));
00206         switch (frametype) {
00207             case NUV_EXTRADATA:
00208                 if (!ctx->rtjpg_video) {
00209                     url_fskip(pb, size);
00210                     break;
00211                 }
00212             case NUV_VIDEO:
00213                 if (ctx->v_id < 0) {
00214                     av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n");
00215                     url_fskip(pb, size);
00216                     break;
00217                 }
00218                 ret = av_new_packet(pkt, copyhdrsize + size);
00219                 if (ret < 0)
00220                     return ret;
00221                 // HACK: we have no idea if it is a keyframe,
00222                 // but if we mark none seeking will not work at all.
00223                 pkt->flags |= AV_PKT_FLAG_KEY;
00224                 pkt->pos = pos;
00225                 pkt->pts = AV_RL32(&hdr[4]);
00226                 pkt->stream_index = ctx->v_id;
00227                 memcpy(pkt->data, hdr, copyhdrsize);
00228                 ret = get_buffer(pb, pkt->data + copyhdrsize, size);
00229                 if (ret < 0) {
00230                     av_free_packet(pkt);
00231                     return ret;
00232                 }
00233                 if (ret < size)
00234                     av_shrink_packet(pkt, copyhdrsize + ret);
00235                 return 0;
00236             case NUV_AUDIO:
00237                 if (ctx->a_id < 0) {
00238                     av_log(s, AV_LOG_ERROR, "Audio packet in file without audio stream!\n");
00239                     url_fskip(pb, size);
00240                     break;
00241                 }
00242                 ret = av_get_packet(pb, pkt, size);
00243                 pkt->flags |= AV_PKT_FLAG_KEY;
00244                 pkt->pos = pos;
00245                 pkt->pts = AV_RL32(&hdr[4]);
00246                 pkt->stream_index = ctx->a_id;
00247                 if (ret < 0) return ret;
00248                 return 0;
00249             case NUV_SEEKP:
00250                 // contains no data, size value is invalid
00251                 break;
00252             default:
00253                 url_fskip(pb, size);
00254                 break;
00255         }
00256     }
00257     return AVERROR(EIO);
00258 }
00259 
00260 AVInputFormat nuv_demuxer = {
00261     "nuv",
00262     NULL_IF_CONFIG_SMALL("NuppelVideo format"),
00263     sizeof(NUVContext),
00264     nuv_probe,
00265     nuv_header,
00266     nuv_packet,
00267     NULL,
00268     NULL,
00269     .flags = AVFMT_GENERIC_INDEX,
00270 };

Generated on Fri Sep 16 2011 17:17:41 for FFmpeg by  doxygen 1.7.1