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(ByteIOContext *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 = 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);
00086 if (vst) {
00087 vst->codec->codec_tag = get_le32(pb);
00088 vst->codec->codec_id =
00089 codec_get_id(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 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], version_string[5];
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 get_buffer(pb, version_string, 5);
00134 url_fskip(pb, 3);
00135 width = get_le32(pb);
00136 height = get_le32(pb);
00137 get_le32(pb);
00138 get_le32(pb);
00139 get_byte(pb);
00140 url_fskip(pb, 3);
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
00147 v_packs = get_le32(pb);
00148 a_packs = get_le32(pb);
00149 get_le32(pb);
00150
00151 get_le32(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 = CODEC_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 = CODEC_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 ret = get_buffer(pb, hdr, HDRSIZE);
00201 if (ret <= 0)
00202 return ret ? ret : -1;
00203 frametype = hdr[0];
00204 size = PKTSIZE(AV_RL32(&hdr[8]));
00205 switch (frametype) {
00206 case NUV_EXTRADATA:
00207 if (!ctx->rtjpg_video) {
00208 url_fskip(pb, size);
00209 break;
00210 }
00211 case NUV_VIDEO:
00212 if (ctx->v_id < 0) {
00213 av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n");
00214 url_fskip(pb, size);
00215 break;
00216 }
00217 ret = av_new_packet(pkt, copyhdrsize + size);
00218 if (ret < 0)
00219 return ret;
00220 pkt->pos = url_ftell(pb) - copyhdrsize;
00221 pkt->pts = AV_RL32(&hdr[4]);
00222 pkt->stream_index = ctx->v_id;
00223 memcpy(pkt->data, hdr, copyhdrsize);
00224 ret = get_buffer(pb, pkt->data + copyhdrsize, size);
00225 return ret;
00226 case NUV_AUDIO:
00227 if (ctx->a_id < 0) {
00228 av_log(s, AV_LOG_ERROR, "Audio packet in file without audio stream!\n");
00229 url_fskip(pb, size);
00230 break;
00231 }
00232 ret = av_get_packet(pb, pkt, size);
00233 pkt->pts = AV_RL32(&hdr[4]);
00234 pkt->stream_index = ctx->a_id;
00235 return ret;
00236 case NUV_SEEKP:
00237
00238 break;
00239 default:
00240 url_fskip(pb, size);
00241 break;
00242 }
00243 }
00244 return AVERROR(EIO);
00245 }
00246
00247 AVInputFormat nuv_demuxer = {
00248 "nuv",
00249 NULL_IF_CONFIG_SMALL("NuppelVideo format"),
00250 sizeof(NUVContext),
00251 nuv_probe,
00252 nuv_header,
00253 nuv_packet,
00254 NULL,
00255 NULL,
00256 };