... | ... |
@@ -28,6 +28,10 @@ |
28 | 28 |
|
29 | 29 |
typedef struct { |
30 | 30 |
int64_t data; |
31 |
+ uint8_t *pkt_sizes; |
|
32 |
+ int size_buffer_size; |
|
33 |
+ int size_entries_used; |
|
34 |
+ int packets; |
|
31 | 35 |
} CAFContext; |
32 | 36 |
|
33 | 37 |
static uint32_t codec_flags(enum CodecID codec_id) { |
... | ... |
@@ -133,9 +137,9 @@ static int caf_write_header(AVFormatContext *s) |
133 | 133 |
return AVERROR_INVALIDDATA; |
134 | 134 |
} |
135 | 135 |
|
136 |
- if (!enc->block_align) { |
|
137 |
- av_log(s, AV_LOG_ERROR, "muxing with unknown or variable packet size not yet supported\n"); |
|
138 |
- return AVERROR_PATCHWELCOME; |
|
136 |
+ if (!enc->block_align && !pb->seekable) { |
|
137 |
+ av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n"); |
|
138 |
+ return AVERROR_INVALIDDATA; |
|
139 | 139 |
} |
140 | 140 |
|
141 | 141 |
ffio_wfourcc(pb, "caff"); //< mFileType |
... | ... |
@@ -169,13 +173,38 @@ static int caf_write_header(AVFormatContext *s) |
169 | 169 |
|
170 | 170 |
static int caf_write_packet(AVFormatContext *s, AVPacket *pkt) |
171 | 171 |
{ |
172 |
+ CAFContext *caf = s->priv_data; |
|
173 |
+ |
|
172 | 174 |
avio_write(s->pb, pkt->data, pkt->size); |
175 |
+ if (!s->streams[0]->codec->block_align) { |
|
176 |
+ void *pkt_sizes = caf->pkt_sizes; |
|
177 |
+ int i, alloc_size = caf->size_entries_used + 5; |
|
178 |
+ if (alloc_size < 0) { |
|
179 |
+ caf->pkt_sizes = NULL; |
|
180 |
+ } else { |
|
181 |
+ caf->pkt_sizes = av_fast_realloc(caf->pkt_sizes, |
|
182 |
+ &caf->size_buffer_size, |
|
183 |
+ alloc_size); |
|
184 |
+ } |
|
185 |
+ if (!caf->pkt_sizes) { |
|
186 |
+ av_free(pkt_sizes); |
|
187 |
+ return AVERROR(ENOMEM); |
|
188 |
+ } |
|
189 |
+ for (i = 4; i > 0; i--) { |
|
190 |
+ unsigned top = pkt->size >> i * 7; |
|
191 |
+ if (top) |
|
192 |
+ caf->pkt_sizes[caf->size_entries_used++] = 128 | top; |
|
193 |
+ } |
|
194 |
+ caf->pkt_sizes[caf->size_entries_used++] = pkt->size & 127; |
|
195 |
+ caf->packets++; |
|
196 |
+ } |
|
173 | 197 |
return 0; |
174 | 198 |
} |
175 | 199 |
|
176 | 200 |
static int caf_write_trailer(AVFormatContext *s) |
177 | 201 |
{ |
178 | 202 |
AVIOContext *pb = s->pb; |
203 |
+ AVCodecContext *enc = s->streams[0]->codec; |
|
179 | 204 |
|
180 | 205 |
if (pb->seekable) { |
181 | 206 |
CAFContext *caf = s->priv_data; |
... | ... |
@@ -184,6 +213,17 @@ static int caf_write_trailer(AVFormatContext *s) |
184 | 184 |
avio_seek(pb, caf->data, SEEK_SET); |
185 | 185 |
avio_wb64(pb, file_size - caf->data - 8); |
186 | 186 |
avio_seek(pb, file_size, SEEK_SET); |
187 |
+ if (!enc->block_align) { |
|
188 |
+ ffio_wfourcc(pb, "pakt"); |
|
189 |
+ avio_wb64(pb, caf->size_entries_used + 24); |
|
190 |
+ avio_wb64(pb, caf->packets); ///< mNumberPackets |
|
191 |
+ avio_wb64(pb, caf->packets * samples_per_packet(enc->codec_id, enc->channels)); ///< mNumberValidFrames |
|
192 |
+ avio_wb32(pb, 0); ///< mPrimingFrames |
|
193 |
+ avio_wb32(pb, 0); ///< mRemainderFrames |
|
194 |
+ avio_write(pb, caf->pkt_sizes, caf->size_entries_used); |
|
195 |
+ av_freep(&caf->pkt_sizes); |
|
196 |
+ caf->size_buffer_size = 0; |
|
197 |
+ } |
|
187 | 198 |
avio_flush(pb); |
188 | 199 |
} |
189 | 200 |
return 0; |