Mercurial > libavformat.hg
comparison a64.c @ 6415:d2ca6ecc8b43 libavformat
Added option to write frames interleaved (yet disabled)
For this reason, a MuxerContext and write_trailer()-function was added,
to track the previous packet and flush the last packet at the end.
author | bindhammer |
---|---|
date | Thu, 26 Aug 2010 10:03:09 +0000 |
parents | 33ebda64cac1 |
children | e60cca9e99a3 |
comparison
equal
deleted
inserted
replaced
6414:1c0b01ca809d | 6415:d2ca6ecc8b43 |
---|---|
22 #include "libavcodec/avcodec.h" | 22 #include "libavcodec/avcodec.h" |
23 #include "libavcodec/a64enc.h" | 23 #include "libavcodec/a64enc.h" |
24 #include "libavcodec/bytestream.h" | 24 #include "libavcodec/bytestream.h" |
25 #include "avformat.h" | 25 #include "avformat.h" |
26 | 26 |
27 typedef struct A64MuxerContext { | |
28 int interleaved; | |
29 AVPacket prev_pkt; | |
30 int prev_frame_count; | |
31 } A64MuxerContext; | |
32 | |
27 static int a64_write_header(struct AVFormatContext *s) | 33 static int a64_write_header(struct AVFormatContext *s) |
28 { | 34 { |
29 AVCodecContext *avctx=s->streams[0]->codec; | 35 AVCodecContext *avctx=s->streams[0]->codec; |
36 A64MuxerContext *c = s->priv_data; | |
30 uint8_t header[5] = { | 37 uint8_t header[5] = { |
31 0x00, //load | 38 0x00, //load |
32 0x40, //address | 39 0x40, //address |
33 0x00, //mode | 40 0x00, //mode |
34 0x00, //charset_lifetime (multi only) | 41 0x00, //charset_lifetime (multi only) |
35 0x00 //fps in 50/fps; | 42 0x00 //fps in 50/fps; |
36 }; | 43 }; |
44 c->interleaved = 0; | |
37 switch (avctx->codec->id) { | 45 switch (avctx->codec->id) { |
38 case CODEC_ID_A64_MULTI: | 46 case CODEC_ID_A64_MULTI: |
39 header[2] = 0x00; | 47 header[2] = 0x00; |
40 header[3] = 4; | 48 header[3] = 4; |
41 header[4] = 2; | 49 header[4] = 2; |
48 default: | 56 default: |
49 return AVERROR(EINVAL); | 57 return AVERROR(EINVAL); |
50 break; | 58 break; |
51 } | 59 } |
52 put_buffer(s->pb, header, 2); | 60 put_buffer(s->pb, header, 2); |
61 c->prev_pkt.size = 0; | |
62 c->prev_frame_count = 0; | |
53 return 0; | 63 return 0; |
54 } | 64 } |
55 | 65 |
56 static int a64_write_packet(struct AVFormatContext *s, AVPacket *pkt) | 66 static int a64_write_packet(struct AVFormatContext *s, AVPacket *pkt) |
57 { | 67 { |
58 put_buffer(s->pb, pkt->data, pkt->size); | 68 AVCodecContext *avctx = s->streams[0]->codec; |
69 A64MuxerContext *c = s->priv_data; | |
70 int i, j; | |
71 int ch_chunksize; | |
72 int lifetime; | |
73 int frame_count; | |
74 int charset_size; | |
75 int frame_size; | |
76 int num_frames; | |
77 | |
78 /* fetch values from extradata */ | |
79 switch (avctx->codec->id) { | |
80 case CODEC_ID_A64_MULTI: | |
81 case CODEC_ID_A64_MULTI5: | |
82 if(c->interleaved) { | |
83 /* Write interleaved, means we insert chunks of the future charset before each current frame. | |
84 * Reason: if we load 1 charset + corresponding frames in one block on c64, we need to store | |
85 * them first and then display frame by frame to keep in sync. Thus we would read and write | |
86 * the data for colram from/to ram first and waste too much time. If we interleave and send the | |
87 * charset beforehand, we assemble a new charset chunk by chunk, write current screen data to | |
88 * screen-ram to be displayed and decode the colram directly to colram-location $d800 during | |
89 * the overscan, while reading directly from source | |
90 * This is the only way so far, to achieve 25fps on c64 */ | |
91 if(avctx->extradata) { | |
92 /* fetch values from extradata */ | |
93 lifetime = AV_RB32(avctx->extradata + 0); | |
94 frame_count = AV_RB32(avctx->extradata + 4); | |
95 charset_size = AV_RB32(avctx->extradata + 8); | |
96 frame_size = AV_RB32(avctx->extradata + 12); | |
97 | |
98 /* TODO: sanity checks? */ | |
99 } | |
100 else { | |
101 av_log(avctx, AV_LOG_ERROR, "extradata not set\n"); | |
102 return AVERROR(EINVAL); | |
103 } | |
104 ch_chunksize=charset_size/lifetime; | |
105 /* TODO: check if charset/size is % lifetime, but maybe check in codec */ | |
106 if(pkt->data) num_frames = lifetime; | |
107 else num_frames = c->prev_frame_count; | |
108 for(i = 0; i < num_frames; i++) { | |
109 if(pkt->data) { | |
110 /* if available, put newest charset chunk into buffer */ | |
111 put_buffer(s->pb, pkt->data + ch_chunksize * i, ch_chunksize); | |
112 } | |
113 else { | |
114 /* a bit ugly, but is there an alternative to put many zeros? */ | |
115 for(j = 0; j < ch_chunksize; j++) put_byte(s->pb, 0); | |
116 } | |
117 if(c->prev_pkt.data) { | |
118 /* put frame (screen + colram) from last packet into buffer */ | |
119 put_buffer(s->pb, c->prev_pkt.data + charset_size + frame_size * i, frame_size); | |
120 } | |
121 else { | |
122 /* a bit ugly, but is there an alternative to put many zeros? */ | |
123 for(j = 0; j < frame_size; j++) put_byte(s->pb, 0); | |
124 } | |
125 } | |
126 /* backup current packet for next turn */ | |
127 if(pkt->data) { | |
128 av_new_packet(&c->prev_pkt, pkt->size); | |
129 memcpy(c->prev_pkt.data, pkt->data, pkt->size); | |
130 } | |
131 c->prev_frame_count = frame_count; | |
132 break; | |
133 } | |
134 default: | |
135 /* Write things as is. Nice for self-contained frames from non-multicolor modes or if played | |
136 * directly from ram and not from a streaming device (rrnet/mmc) */ | |
137 if(pkt) put_buffer(s->pb, pkt->data, pkt->size); | |
138 break; | |
139 } | |
140 | |
59 put_flush_packet(s->pb); | 141 put_flush_packet(s->pb); |
142 return 0; | |
143 } | |
144 | |
145 static int a64_write_trailer(struct AVFormatContext *s) | |
146 { | |
147 A64MuxerContext *c = s->priv_data; | |
148 AVPacket pkt; | |
149 /* need to flush last packet? */ | |
150 if(c->interleaved) a64_write_packet(s, &pkt); | |
60 return 0; | 151 return 0; |
61 } | 152 } |
62 | 153 |
63 AVOutputFormat a64_muxer = { | 154 AVOutputFormat a64_muxer = { |
64 .name = "a64", | 155 .name = "a64", |
67 .extensions = "a64, A64", | 158 .extensions = "a64, A64", |
68 .priv_data_size = sizeof (A64Context), | 159 .priv_data_size = sizeof (A64Context), |
69 .video_codec = CODEC_ID_A64_MULTI, | 160 .video_codec = CODEC_ID_A64_MULTI, |
70 a64_write_header, | 161 a64_write_header, |
71 a64_write_packet, | 162 a64_write_packet, |
163 a64_write_trailer | |
72 }; | 164 }; |