X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fasfenc.c;h=f6608d52923b0ff0f4f7b47978877c5f80171d36;hb=cc8db760616a7ec3bd39b22ca45888c01326db13;hp=a523b3a0515ca161928ef2a0fa9fbe44ada5a7d0;hpb=3cd93cc7b898f83cc0c7ae35804dbe2cb6586af2;p=ffmpeg diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c index a523b3a0515..f6608d52923 100644 --- a/libavformat/asfenc.c +++ b/libavformat/asfenc.c @@ -20,6 +20,7 @@ */ #include "libavutil/dict.h" +#include "libavutil/mathematics.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" @@ -182,7 +183,30 @@ 1 - /* Payload Flags */ \ 2 * PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS) -typedef struct { +#define DATA_HEADER_SIZE 50 + +typedef struct ASFStream { + int num; + unsigned char seq; + /* use for reading */ + AVPacket pkt; + int frag_offset; + int timestamp; + int64_t duration; + + int ds_span; /* descrambling */ + int ds_packet_size; + int ds_chunk_size; + + int64_t packet_pos; + + uint16_t stream_language_index; + + int palette_changed; + uint32_t palette[256]; +} ASFStream; + +typedef struct ASFContext { uint32_t seqno; int is_streamed; ASFStream streams[128]; ///< it's max number and it's not that big @@ -285,6 +309,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->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) @@ -386,7 +468,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; @@ -466,14 +553,11 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, 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); @@ -485,17 +569,24 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, 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 */ @@ -517,14 +608,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,11 +646,12 @@ static int asf_write_header(AVFormatContext *s) 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); + av_freep(&asf->index_ptr); return -1; } @@ -760,12 +852,14 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst, 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]; @@ -788,14 +882,20 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) 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)); }