summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat/asfenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavformat/asfenc.c')
-rw-r--r--ffmpeg/libavformat/asfenc.c127
1 files changed, 108 insertions, 19 deletions
diff --git a/ffmpeg/libavformat/asfenc.c b/ffmpeg/libavformat/asfenc.c
index f3aec9c..8e343b3 100644
--- a/ffmpeg/libavformat/asfenc.c
+++ b/ffmpeg/libavformat/asfenc.c
@@ -19,7 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/avassert.h"
#include "libavutil/dict.h"
+#include "libavutil/mathematics.h"
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
@@ -182,6 +184,8 @@
1 - /* Payload Flags */ \
2 * PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS)
+#define DATA_HEADER_SIZE 50
+
typedef struct {
uint32_t seqno;
int is_streamed;
@@ -205,6 +209,7 @@ typedef struct {
uint16_t maximum_packet;
uint32_t next_packet_number;
uint16_t next_packet_count;
+ uint64_t next_packet_offset;
int next_start_sec;
int end_sec;
} ASFContext;
@@ -220,7 +225,7 @@ static const AVCodecTag codec_asf_bmp_tags[] = {
void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
{
- assert(sizeof(*g) == 16);
+ av_assert0(sizeof(*g) == 16);
avio_write(s, *g, sizeof(*g));
}
@@ -287,6 +292,64 @@ static int64_t unix_to_file_time(int ti)
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->next_start_sec; 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);
+
+ ff_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)
@@ -388,7 +451,12 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_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;
@@ -457,7 +525,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
avio_wl16(pb, 40 + enc->extradata_size); /* size */
/* BITMAPINFOHEADER header */
- ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1);
+ ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1, 0);
}
end_header(pb, hpos);
}
@@ -519,14 +587,14 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
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);
@@ -555,10 +623,10 @@ static int asf_write_header(AVFormatContext *s)
asf->nb_index_memory_alloc = ASF_INDEX_BLOCK;
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;
}
@@ -600,7 +668,7 @@ static int put_payload_parsing_info(AVFormatContext *s,
padsize -= PACKET_HEADER_MIN_SIZE;
if (asf->multi_payloads_present)
padsize--;
- assert(padsize >= 0);
+ av_assert0(padsize >= 0);
avio_w8(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS);
for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++)
@@ -639,7 +707,7 @@ static void flush_packet(AVFormatContext *s)
ASFContext *asf = s->priv_data;
int packet_hdr_size, packet_filled_size;
- assert(asf->packet_timestamp_end >= asf->packet_timestamp_start);
+ av_assert0(asf->packet_timestamp_end >= asf->packet_timestamp_start);
if (asf->is_streamed)
put_chunk(s, 0x4424, s->packet_size, 0);
@@ -651,7 +719,7 @@ static void flush_packet(AVFormatContext *s)
asf->packet_size_left);
packet_filled_size = PACKET_SIZE - asf->packet_size_left;
- assert(packet_hdr_size <= asf->packet_size_left);
+ av_assert0(packet_hdr_size <= asf->packet_size_left);
memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
avio_write(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size);
@@ -759,8 +827,9 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
stream->seq++;
}
-static void update_index(AVFormatContext *s, int start_sec,
- uint32_t packet_number, uint16_t packet_count)
+static int update_index(AVFormatContext *s, int start_sec,
+ uint32_t packet_number, uint16_t packet_count,
+ uint64_t packet_offset)
{
ASFContext *asf = s->priv_data;
@@ -770,32 +839,48 @@ static void update_index(AVFormatContext *s, int start_sec,
if (!asf->next_start_sec) {
asf->next_packet_number = packet_number;
asf->next_packet_count = packet_count;
+ asf->next_packet_offset = packet_offset;
}
if (start_sec > asf->nb_index_memory_alloc) {
+ int err;
asf->nb_index_memory_alloc = (start_sec + ASF_INDEX_BLOCK) & ~(ASF_INDEX_BLOCK - 1);
- asf->index_ptr = 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;
+ }
}
for (i = asf->next_start_sec; i < start_sec; i++) {
asf->index_ptr[i].packet_number = asf->next_packet_number;
asf->index_ptr[i].packet_count = asf->next_packet_count;
+ asf->index_ptr[i].send_time = asf->next_start_sec * INT64_C(10000000);
+ asf->index_ptr[i].offset = asf->next_packet_offset;
+
}
}
asf->maximum_packet = FFMAX(asf->maximum_packet, packet_count);
asf->next_packet_number = packet_number;
asf->next_packet_count = packet_count;
+ asf->next_packet_offset = packet_offset;
asf->next_start_sec = start_sec;
+
+ return 0;
}
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
ASFStream *stream;
AVCodecContext *codec;
uint32_t packet_number;
int64_t pts;
int start_sec;
int flags = pkt->flags;
+ int ret;
+ uint64_t offset = avio_tell(pb);
codec = s->streams[pkt->stream_index]->codec;
stream = &asf->streams[pkt->stream_index];
@@ -804,7 +889,7 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
flags &= ~AV_PKT_FLAG_KEY;
pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts;
- assert(pts != AV_NOPTS_VALUE);
+ av_assert0(pts != AV_NOPTS_VALUE);
pts *= 10000;
asf->duration = FFMAX(asf->duration, pts + pkt->duration * 10000);
@@ -818,7 +903,9 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
/* check index */
if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
uint16_t packet_count = asf->nb_packets - packet_number;
- update_index(s, start_sec, packet_number, packet_count);
+ ret = update_index(s, start_sec, packet_number, packet_count, offset);
+ if (ret < 0)
+ return ret;
}
asf->end_sec = start_sec;
@@ -849,6 +936,7 @@ static int asf_write_trailer(AVFormatContext *s)
{
ASFContext *asf = s->priv_data;
int64_t file_size, data_size;
+ int ret;
/* flush the current packet */
if (asf->pb.buf_ptr > asf->pb.buffer)
@@ -857,7 +945,8 @@ static int asf_write_trailer(AVFormatContext *s)
/* write index */
data_size = avio_tell(s->pb);
if (!asf->is_streamed && asf->next_start_sec) {
- update_index(s, asf->end_sec + 1, 0, 0);
+ if ((ret = update_index(s, asf->end_sec + 1, 0, 0, 0)) < 0)
+ return ret;
asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->next_start_sec);
}
avio_flush(s->pb);
@@ -871,7 +960,7 @@ static int asf_write_trailer(AVFormatContext *s)
asf_write_header1(s, file_size, data_size - asf->data_offset);
}
- av_free(asf->index_ptr);
+ av_freep(&asf->index_ptr);
return 0;
}