*/
#include "libavutil/dict.h"
+#include "libavutil/mathematics.h"
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
1 - /* Payload Flags */ \
2 * PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS)
+#define DATA_HEADER_SIZE 50
+
typedef struct {
uint32_t seqno;
int is_streamed;
return t;
}
+static int32_t get_send_time(ASFContext *asf, int64_t pres_time, uint64_t *offset)
+{
+ int i;
+ int32_t send_time = 0;
+ *offset = asf->data_offset + DATA_HEADER_SIZE;
+ for (i = 0; i < asf->nb_index_count; i++) {
+ if (pres_time <= asf->index_ptr[i].send_time)
+ break;
+ send_time = asf->index_ptr[i].send_time;
+ *offset = asf->index_ptr[i].offset;
+ }
+
+ return send_time / 10000;
+}
+
+static int asf_write_markers(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int i;
+ AVRational scale = {1, 10000000};
+ int64_t hpos = put_header(pb, &ff_asf_marker_header);
+
+ put_guid(pb, &ff_asf_reserved_4); // ASF spec mandates this reserved value
+ avio_wl32(pb, s->nb_chapters); // markers count
+ avio_wl16(pb, 0); // ASF spec mandates 0 for this
+ avio_wl16(pb, 0); // name length 0, no name given
+
+ for (i = 0; i < s->nb_chapters; i++) {
+ AVChapter *c = s->chapters[i];
+ AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
+ int64_t pres_time = av_rescale_q(c->start, c->time_base, scale);
+ uint64_t offset;
+ int32_t send_time = get_send_time(asf, pres_time, &offset);
+ int len = 0;
+ uint8_t *buf;
+ AVIOContext *dyn_buf;
+ if (t) {
+ if (avio_open_dyn_buf(&dyn_buf) < 0)
+ return AVERROR(ENOMEM);
+ avio_put_str16le(dyn_buf, t->value);
+ len = avio_close_dyn_buf(dyn_buf, &buf);
+ }
+ avio_wl64(pb, offset); // offset of the packet with send_time
+ avio_wl64(pb, pres_time + PREROLL_TIME * 10000); // presentation time
+ avio_wl16(pb, 12 + len); // entry length
+ avio_wl32(pb, send_time); // send time
+ avio_wl32(pb, 0); // flags, should be 0
+ avio_wl32(pb, len / 2); // marker desc length in WCHARS!
+ if (t) {
+ avio_write(pb, buf, len); // marker desc
+ av_freep(&buf);
+ }
+ }
+ end_header(pb, hpos);
+ return 0;
+}
+
/* write the header (used two times if non streamed) */
static int asf_write_header1(AVFormatContext *s, int64_t file_size,
int64_t data_chunk_size)
}
end_header(pb, hpos);
}
-
+ /* chapters using ASF markers */
+ if (!asf->is_streamed && s->nb_chapters) {
+ int ret;
+ if (ret = asf_write_markers(s))
+ return ret;
+ }
/* stream headers */
for (n = 0; n < s->nb_streams; n++) {
int64_t es_pos;
put_guid(pb, &ff_asf_codec_comment1_header);
avio_wl32(pb, s->nb_streams);
for (n = 0; n < s->nb_streams; n++) {
- AVCodec *p;
+ const AVCodecDescriptor *codec_desc;
const char *desc;
- int len;
- uint8_t *buf;
- AVIOContext *dyn_buf;
- enc = s->streams[n]->codec;
- p = avcodec_find_encoder(enc->codec_id);
+ enc = s->streams[n]->codec;
+ codec_desc = avcodec_descriptor_get(enc->codec_id);
if (enc->codec_type == AVMEDIA_TYPE_AUDIO)
avio_wl16(pb, 2);
if (enc->codec_id == AV_CODEC_ID_WMAV2)
desc = "Windows Media Audio V8";
else
- desc = p ? p->name : enc->codec_name;
+ desc = codec_desc ? codec_desc->name : NULL;
- if (avio_open_dyn_buf(&dyn_buf) < 0)
- return AVERROR(ENOMEM);
+ if (desc) {
+ AVIOContext *dyn_buf;
+ uint8_t *buf;
+ int len;
- avio_put_str16le(dyn_buf, desc);
- len = avio_close_dyn_buf(dyn_buf, &buf);
- avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2
+ if (avio_open_dyn_buf(&dyn_buf) < 0)
+ return AVERROR(ENOMEM);
- avio_write(pb, buf, len);
- av_freep(&buf);
+ avio_put_str16le(dyn_buf, desc);
+ len = avio_close_dyn_buf(dyn_buf, &buf);
+ avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2
+
+ avio_write(pb, buf, len);
+ av_freep(&buf);
+ } else
+ avio_wl16(pb, 0);
avio_wl16(pb, 0); /* no parameters */
cur_pos = avio_tell(pb);
header_size = cur_pos - header_offset;
if (asf->is_streamed) {
- header_size += 8 + 30 + 50;
+ header_size += 8 + 30 + DATA_HEADER_SIZE;
avio_seek(pb, header_offset - 10 - 30, SEEK_SET);
avio_wl16(pb, header_size);
avio_seek(pb, header_offset - 2 - 30, SEEK_SET);
avio_wl16(pb, header_size);
- header_size -= 8 + 30 + 50;
+ header_size -= 8 + 30 + DATA_HEADER_SIZE;
}
header_size += 24 + 6;
avio_seek(pb, header_offset - 14, SEEK_SET);
asf->nb_index_count = 0;
asf->maximum_packet = 0;
- /* the data-chunk-size has to be 50, which is data_size - asf->data_offset
- * at the moment this function is done. It is needed to use asf as
- * streamable format. */
- if (asf_write_header1(s, 0, 50) < 0) {
+ /* the data-chunk-size has to be 50 (DATA_HEADER_SIZE), which is
+ * data_size - asf->data_offset at the moment this function is done.
+ * It is needed to use asf as a streamable format. */
+ if (asf_write_header1(s, 0, DATA_HEADER_SIZE) < 0) {
//av_free(asf);
return -1;
}
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
ASFStream *stream;
int64_t duration;
AVCodecContext *codec;
int64_t packet_st, pts;
int start_sec, i;
int flags = pkt->flags;
+ uint64_t offset = avio_tell(pb);
codec = s->streams[pkt->stream_index]->codec;
stream = &asf->streams[pkt->stream_index];
if (start_sec != (int)(asf->last_indexed_pts / INT64_C(10000000))) {
for (i = asf->nb_index_count; i < start_sec; i++) {
if (i >= asf->nb_index_memory_alloc) {
+ int err;
asf->nb_index_memory_alloc += ASF_INDEX_BLOCK;
- asf->index_ptr = (ASFIndex *)av_realloc(asf->index_ptr,
- sizeof(ASFIndex) *
- asf->nb_index_memory_alloc);
+ if ((err = av_reallocp_array(&asf->index_ptr,
+ asf->nb_index_memory_alloc,
+ sizeof(*asf->index_ptr))) < 0) {
+ asf->nb_index_memory_alloc = 0;
+ return err;
+ }
}
// store
asf->index_ptr[i].packet_number = (uint32_t)packet_st;
asf->index_ptr[i].packet_count = (uint16_t)(asf->nb_packets - packet_st);
+ asf->index_ptr[i].send_time = start_sec * INT64_C(10000000);
+ asf->index_ptr[i].offset = offset;
asf->maximum_packet = FFMAX(asf->maximum_packet,
(uint16_t)(asf->nb_packets - packet_st));
}