00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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(AVIOContext *pb, AVStream *vst,
00059 AVStream *ast, int myth) {
00060 nuv_frametype frametype;
00061 if (!vst && !myth)
00062 return 1;
00063 while (!url_feof(pb)) {
00064 int size, subtype;
00065 frametype = avio_r8(pb);
00066 switch (frametype) {
00067 case NUV_EXTRADATA:
00068 subtype = avio_r8(pb);
00069 avio_skip(pb, 6);
00070 size = PKTSIZE(avio_rl32(pb));
00071 if (vst && subtype == 'R') {
00072 vst->codec->extradata_size = size;
00073 vst->codec->extradata = av_malloc(size);
00074 avio_read(pb, vst->codec->extradata, size);
00075 size = 0;
00076 if (!myth)
00077 return 1;
00078 }
00079 break;
00080 case NUV_MYTHEXT:
00081 avio_skip(pb, 7);
00082 size = PKTSIZE(avio_rl32(pb));
00083 if (size != 128 * 4)
00084 break;
00085 avio_rl32(pb);
00086 if (vst) {
00087 vst->codec->codec_tag = avio_rl32(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 avio_skip(pb, 4);
00094
00095 if (ast) {
00096 ast->codec->codec_tag = avio_rl32(pb);
00097 ast->codec->sample_rate = avio_rl32(pb);
00098 ast->codec->bits_per_coded_sample = avio_rl32(pb);
00099 ast->codec->channels = avio_rl32(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 avio_skip(pb, 4 * 4);
00106
00107 size -= 6 * 4;
00108 avio_skip(pb, size);
00109 return 1;
00110 case NUV_SEEKP:
00111 size = 11;
00112 break;
00113 default:
00114 avio_skip(pb, 7);
00115 size = PKTSIZE(avio_rl32(pb));
00116 break;
00117 }
00118 avio_skip(pb, size);
00119 }
00120 return 0;
00121 }
00122
00123 static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) {
00124 NUVContext *ctx = s->priv_data;
00125 AVIOContext *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 avio_read(pb, id_string, 12);
00132 is_mythtv = !memcmp(id_string, "MythTVVideo", 12);
00133 avio_skip(pb, 5);
00134 avio_skip(pb, 3);
00135 width = avio_rl32(pb);
00136 height = avio_rl32(pb);
00137 avio_rl32(pb);
00138 avio_rl32(pb);
00139 avio_r8(pb);
00140 avio_skip(pb, 3);
00141 aspect = av_int2dbl(avio_rl64(pb));
00142 if (aspect > 0.9999 && aspect < 1.0001)
00143 aspect = 4.0 / 3.0;
00144 fps = av_int2dbl(avio_rl64(pb));
00145
00146
00147 v_packs = avio_rl32(pb);
00148 a_packs = avio_rl32(pb);
00149 avio_rl32(pb);
00150
00151 avio_rl32(pb);
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 AVIOContext *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 = avio_tell(pb);
00201 ret = avio_read(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 avio_skip(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 avio_skip(pb, size);
00216 break;
00217 }
00218 ret = av_new_packet(pkt, copyhdrsize + size);
00219 if (ret < 0)
00220 return ret;
00221
00222
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 = avio_read(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 avio_skip(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
00251 break;
00252 default:
00253 avio_skip(pb, size);
00254 break;
00255 }
00256 }
00257 return AVERROR(EIO);
00258 }
00259
00260 AVInputFormat ff_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 };