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 break;
00059 }
00060 avio_write(s->pb, header, 2);
00061 c->prev_pkt.size = 0;
00062 c->prev_frame_count = 0;
00063 return 0;
00064 }
00065
00066 static int a64_write_packet(struct AVFormatContext *s, AVPacket *pkt)
00067 {
00068 AVCodecContext *avctx = s->streams[0]->codec;
00069 A64MuxerContext *c = s->priv_data;
00070 int i, j;
00071 int ch_chunksize;
00072 int lifetime;
00073 int frame_count;
00074 int charset_size;
00075 int frame_size;
00076 int num_frames;
00077
00078
00079 switch (avctx->codec->id) {
00080 case CODEC_ID_A64_MULTI:
00081 case CODEC_ID_A64_MULTI5:
00082 if(c->interleaved) {
00083
00084
00085
00086
00087
00088
00089
00090
00091 if(avctx->extradata) {
00092
00093 lifetime = AV_RB32(avctx->extradata + 0);
00094 frame_count = AV_RB32(avctx->extradata + 4);
00095 charset_size = AV_RB32(avctx->extradata + 8);
00096 frame_size = AV_RB32(avctx->extradata + 12);
00097
00098
00099 } else {
00100 av_log(avctx, AV_LOG_ERROR, "extradata not set\n");
00101 return AVERROR(EINVAL);
00102 }
00103
00104 ch_chunksize=charset_size/lifetime;
00105
00106
00107 if(pkt->data) num_frames = lifetime;
00108 else num_frames = c->prev_frame_count;
00109
00110 for(i = 0; i < num_frames; i++) {
00111 if(pkt->data) {
00112
00113 avio_write(s->pb, pkt->data + ch_chunksize * i, ch_chunksize);
00114 } else {
00115
00116 for(j = 0; j < ch_chunksize; j++) avio_w8(s->pb, 0);
00117 }
00118
00119 if(c->prev_pkt.data) {
00120
00121 avio_write(s->pb, c->prev_pkt.data + charset_size + frame_size * i, frame_size);
00122 } else {
00123
00124 for(j = 0; j < frame_size; j++) avio_w8(s->pb, 0);
00125 }
00126 }
00127
00128
00129 if(pkt->data) {
00130
00131 if(!c->prev_pkt.data) av_new_packet(&c->prev_pkt, pkt->size);
00132
00133 if(c->prev_pkt.data && c->prev_pkt.size >= pkt->size) {
00134 memcpy(c->prev_pkt.data, pkt->data, pkt->size);
00135 c->prev_pkt.size = pkt->size;
00136 } else {
00137 av_log(avctx, AV_LOG_ERROR, "Too less memory for prev_pkt.\n");
00138 return AVERROR(ENOMEM);
00139 }
00140 }
00141
00142 c->prev_frame_count = frame_count;
00143 break;
00144 }
00145 default:
00146
00147
00148 if(pkt) avio_write(s->pb, pkt->data, pkt->size);
00149 break;
00150 }
00151
00152 avio_flush(s->pb);
00153 return 0;
00154 }
00155
00156 static int a64_write_trailer(struct AVFormatContext *s)
00157 {
00158 A64MuxerContext *c = s->priv_data;
00159 AVPacket pkt = {0};
00160
00161 if(c->interleaved) a64_write_packet(s, &pkt);
00162
00163 if(c->prev_pkt.data) av_destruct_packet(&c->prev_pkt);
00164 return 0;
00165 }
00166
00167 AVOutputFormat ff_a64_muxer = {
00168 .name = "a64",
00169 .long_name = NULL_IF_CONFIG_SMALL("a64 - video for Commodore 64"),
00170 .mime_type = NULL,
00171 .extensions = "a64, A64",
00172 .priv_data_size = sizeof (A64Context),
00173 .video_codec = CODEC_ID_A64_MULTI,
00174 a64_write_header,
00175 a64_write_packet,
00176 a64_write_trailer
00177 };