00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "avformat.h"
00028 #include "internal.h"
00029 #include "riff.h"
00030 #include "smjpeg.h"
00031
00032 typedef struct SMJPEGMuxContext {
00033 uint32_t duration;
00034 } SMJPEGMuxContext;
00035
00036 static int smjpeg_write_header(AVFormatContext *s)
00037 {
00038 AVDictionaryEntry *t = NULL;
00039 AVIOContext *pb = s->pb;
00040 int n, tag;
00041
00042 if (s->nb_streams > 2) {
00043 av_log(s, AV_LOG_ERROR, "more than >2 streams are not supported\n");
00044 return AVERROR(EINVAL);
00045 }
00046 avio_write(pb, SMJPEG_MAGIC, 8);
00047 avio_wb32(pb, 0);
00048 avio_wb32(pb, 0);
00049
00050 while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
00051 avio_wl32(pb, SMJPEG_TXT);
00052 avio_wb32(pb, strlen(t->key) + strlen(t->value) + 3);
00053 avio_write(pb, t->key, strlen(t->key));
00054 avio_write(pb, " = ", 3);
00055 avio_write(pb, t->value, strlen(t->value));
00056 }
00057
00058 for (n = 0; n < s->nb_streams; n++) {
00059 AVStream *st = s->streams[n];
00060 AVCodecContext *codec = st->codec;
00061 if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
00062 tag = ff_codec_get_tag(ff_codec_smjpeg_audio_tags, codec->codec_id);
00063 if (!tag) {
00064 av_log(s, AV_LOG_ERROR, "unsupported audio codec\n");
00065 return AVERROR(EINVAL);
00066 }
00067 avio_wl32(pb, SMJPEG_SND);
00068 avio_wb32(pb, 8);
00069 avio_wb16(pb, codec->sample_rate);
00070 avio_w8(pb, av_get_bits_per_sample(codec->codec_id));
00071 avio_w8(pb, codec->channels);
00072 avio_wl32(pb, tag);
00073 avpriv_set_pts_info(st, 32, 1, 1000);
00074 } else if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
00075 tag = ff_codec_get_tag(ff_codec_smjpeg_video_tags, codec->codec_id);
00076 if (!tag) {
00077 av_log(s, AV_LOG_ERROR, "unsupported video codec\n");
00078 return AVERROR(EINVAL);
00079 }
00080 avio_wl32(pb, SMJPEG_VID);
00081 avio_wb32(pb, 12);
00082 avio_wb32(pb, 0);
00083 avio_wb16(pb, codec->width);
00084 avio_wb16(pb, codec->height);
00085 avio_wl32(pb, tag);
00086 avpriv_set_pts_info(st, 32, 1, 1000);
00087 }
00088 }
00089
00090 avio_wl32(pb, SMJPEG_HEND);
00091 avio_flush(pb);
00092
00093 return 0;
00094 }
00095
00096 static int smjpeg_write_packet(AVFormatContext *s, AVPacket *pkt)
00097 {
00098 SMJPEGMuxContext *smc = s->priv_data;
00099 AVIOContext *pb = s->pb;
00100 AVStream *st = s->streams[pkt->stream_index];
00101 AVCodecContext *codec = st->codec;
00102
00103 if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
00104 avio_wl32(pb, SMJPEG_SNDD);
00105 else if (codec->codec_type == AVMEDIA_TYPE_VIDEO)
00106 avio_wl32(pb, SMJPEG_VIDD);
00107 else
00108 return 0;
00109
00110 avio_wb32(pb, pkt->pts);
00111 avio_wb32(pb, pkt->size);
00112 avio_write(pb, pkt->data, pkt->size);
00113 avio_flush(pb);
00114
00115 smc->duration = FFMAX(smc->duration, pkt->pts + pkt->duration);
00116 return 0;
00117 }
00118
00119 static int smjpeg_write_trailer(AVFormatContext *s)
00120 {
00121 SMJPEGMuxContext *smc = s->priv_data;
00122 AVIOContext *pb = s->pb;
00123 int64_t currentpos;
00124
00125 if (pb->seekable) {
00126 currentpos = avio_tell(pb);
00127 avio_seek(pb, 12, SEEK_SET);
00128 avio_wb32(pb, smc->duration);
00129 avio_seek(pb, currentpos, SEEK_SET);
00130 }
00131
00132 avio_wl32(pb, SMJPEG_DONE);
00133 avio_flush(pb);
00134
00135 return 0;
00136 }
00137
00138 AVOutputFormat ff_smjpeg_muxer = {
00139 .name = "smjpeg",
00140 .long_name = NULL_IF_CONFIG_SMALL("Loki SDL MJPEG"),
00141 .priv_data_size = sizeof(SMJPEGMuxContext),
00142 .audio_codec = CODEC_ID_PCM_S16LE,
00143 .video_codec = CODEC_ID_MJPEG,
00144 .write_header = smjpeg_write_header,
00145 .write_packet = smjpeg_write_packet,
00146 .write_trailer = smjpeg_write_trailer,
00147 .flags = AVFMT_GLOBALHEADER,
00148 .codec_tag = (const AVCodecTag *const []){ ff_codec_smjpeg_video_tags, ff_codec_smjpeg_audio_tags, 0 },
00149 };