00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavcodec/avcodec.h"
00023 #include "libavcodec/a64enc.h"
00024 #include "libavcodec/bytestream.h"
00025 #include "avformat.h"
00026
00027 typedef struct A64MuxerContext {
00028 int interleaved;
00029 AVPacket prev_pkt;
00030 int prev_frame_count;
00031 } A64MuxerContext;
00032
00033 static int a64_write_header(struct AVFormatContext *s)
00034 {
00035 AVCodecContext *avctx = s->streams[0]->codec;
00036 A64MuxerContext *c = s->priv_data;
00037 uint8_t header[5] = {
00038 0x00,
00039 0x40,
00040 0x00,
00041 0x00,
00042 0x00
00043 };
00044 c->interleaved = 0;
00045 switch (avctx->codec->id) {
00046 case CODEC_ID_A64_MULTI:
00047 header[2] = 0x00;
00048 header[3] = AV_RB32(avctx->extradata+0);
00049 header[4] = 2;
00050 break;
00051 case CODEC_ID_A64_MULTI5:
00052 header[2] = 0x01;
00053 header[3] = AV_RB32(avctx->extradata+0);
00054 header[4] = 3;
00055 break;
00056 default:
00057 return AVERROR(EINVAL);
00058 }
00059 avio_write(s->pb, header, 2);
00060 c->prev_pkt.size = 0;
00061 c->prev_frame_count = 0;
00062 return 0;
00063 }
00064
00065 static int a64_write_packet(struct AVFormatContext *s, AVPacket *pkt)
00066 {
00067 AVCodecContext *avctx = s->streams[0]->codec;
00068 A64MuxerContext *c = s->priv_data;
00069 int i, j;
00070 int ch_chunksize;
00071 int lifetime;
00072 int frame_count;
00073 int charset_size;
00074 int frame_size;
00075 int num_frames;
00076
00077
00078 switch (avctx->codec->id) {
00079 case CODEC_ID_A64_MULTI:
00080 case CODEC_ID_A64_MULTI5:
00081 if(c->interleaved) {
00082
00083
00084
00085
00086
00087
00088
00089
00090 if(avctx->extradata) {
00091
00092 lifetime = AV_RB32(avctx->extradata + 0);
00093 frame_count = AV_RB32(avctx->extradata + 4);
00094 charset_size = AV_RB32(avctx->extradata + 8);
00095 frame_size = AV_RB32(avctx->extradata + 12);
00096
00097
00098 } else {
00099 av_log(avctx, AV_LOG_ERROR, "extradata not set\n");
00100 return AVERROR(EINVAL);
00101 }
00102
00103 ch_chunksize=charset_size/lifetime;
00104
00105
00106 if(pkt->data) num_frames = lifetime;
00107 else num_frames = c->prev_frame_count;
00108
00109 for(i = 0; i < num_frames; i++) {
00110 if(pkt->data) {
00111
00112 avio_write(s->pb, pkt->data + ch_chunksize * i, ch_chunksize);
00113 } else {
00114
00115 for(j = 0; j < ch_chunksize; j++) avio_w8(s->pb, 0);
00116 }
00117
00118 if(c->prev_pkt.data) {
00119
00120 avio_write(s->pb, c->prev_pkt.data + charset_size + frame_size * i, frame_size);
00121 } else {
00122
00123 for(j = 0; j < frame_size; j++) avio_w8(s->pb, 0);
00124 }
00125 }
00126
00127
00128 if(pkt->data) {
00129
00130 if(!c->prev_pkt.data) av_new_packet(&c->prev_pkt, pkt->size);
00131
00132 if(c->prev_pkt.data && c->prev_pkt.size >= pkt->size) {
00133 memcpy(c->prev_pkt.data, pkt->data, pkt->size);
00134 c->prev_pkt.size = pkt->size;
00135 } else {
00136 av_log(avctx, AV_LOG_ERROR, "Too less memory for prev_pkt.\n");
00137 return AVERROR(ENOMEM);
00138 }
00139 }
00140
00141 c->prev_frame_count = frame_count;
00142 break;
00143 }
00144 default:
00145
00146
00147 if(pkt) avio_write(s->pb, pkt->data, pkt->size);
00148 break;
00149 }
00150
00151 avio_flush(s->pb);
00152 return 0;
00153 }
00154
00155 static int a64_write_trailer(struct AVFormatContext *s)
00156 {
00157 A64MuxerContext *c = s->priv_data;
00158 AVPacket pkt = {0};
00159
00160 if(c->interleaved) a64_write_packet(s, &pkt);
00161
00162 if(c->prev_pkt.data) av_destruct_packet(&c->prev_pkt);
00163 return 0;
00164 }
00165
00166 AVOutputFormat ff_a64_muxer = {
00167 .name = "a64",
00168 .long_name = NULL_IF_CONFIG_SMALL("a64 - video for Commodore 64"),
00169 .extensions = "a64, A64",
00170 .priv_data_size = sizeof (A64Context),
00171 .video_codec = CODEC_ID_A64_MULTI,
00172 .write_header = a64_write_header,
00173 .write_packet = a64_write_packet,
00174 .write_trailer = a64_write_trailer
00175 };