00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "subtitles.h"
00023 #include "libavutil/avstring.h"
00024
00025 AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q,
00026 const uint8_t *event, int len, int merge)
00027 {
00028 AVPacket *subs, *sub;
00029
00030 if (merge && q->nb_subs > 0) {
00031
00032
00033 int old_len;
00034 sub = &q->subs[q->nb_subs - 1];
00035 old_len = sub->size;
00036 if (av_grow_packet(sub, len) < 0)
00037 return NULL;
00038 memcpy(sub->data + old_len, event, len);
00039 } else {
00040
00041
00042 if (q->nb_subs >= INT_MAX/sizeof(*q->subs) - 1)
00043 return NULL;
00044 subs = av_fast_realloc(q->subs, &q->allocated_size,
00045 (q->nb_subs + 1) * sizeof(*q->subs));
00046 if (!subs)
00047 return NULL;
00048 q->subs = subs;
00049 sub = &subs[q->nb_subs++];
00050 if (av_new_packet(sub, len) < 0)
00051 return NULL;
00052 sub->destruct = NULL;
00053 sub->flags |= AV_PKT_FLAG_KEY;
00054 sub->pts = sub->dts = 0;
00055 memcpy(sub->data, event, len);
00056 }
00057 return sub;
00058 }
00059
00060 static int cmp_pkt_sub(const void *a, const void *b)
00061 {
00062 const AVPacket *s1 = a;
00063 const AVPacket *s2 = b;
00064 if (s1->pts == s2->pts) {
00065 if (s1->pos == s2->pos)
00066 return 0;
00067 return s1->pos > s2->pos ? 1 : -1;
00068 }
00069 return s1->pts > s2->pts ? 1 : -1;
00070 }
00071
00072 void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q)
00073 {
00074 int i;
00075
00076 qsort(q->subs, q->nb_subs, sizeof(*q->subs), cmp_pkt_sub);
00077 for (i = 0; i < q->nb_subs; i++)
00078 if (q->subs[i].duration == -1 && i < q->nb_subs - 1)
00079 q->subs[i].duration = q->subs[i + 1].pts - q->subs[i].pts;
00080 }
00081
00082 int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt)
00083 {
00084 AVPacket *sub = q->subs + q->current_sub_idx;
00085
00086 if (q->current_sub_idx == q->nb_subs)
00087 return AVERROR_EOF;
00088 *pkt = *sub;
00089 pkt->dts = pkt->pts;
00090 q->current_sub_idx++;
00091 return 0;
00092 }
00093
00094 int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index,
00095 int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
00096 {
00097 if (flags & AVSEEK_FLAG_BYTE) {
00098 return AVERROR(ENOSYS);
00099 } else if (flags & AVSEEK_FLAG_FRAME) {
00100 if (ts < 0 || ts >= q->nb_subs)
00101 return AVERROR(ERANGE);
00102 q->current_sub_idx = ts;
00103 } else {
00104 int i, idx = -1;
00105 int64_t min_ts_diff = INT64_MAX;
00106 int64_t ts_selected;
00107 if (stream_index == -1) {
00108 AVRational time_base = s->streams[0]->time_base;
00109 ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
00110 min_ts = av_rescale_rnd(min_ts, time_base.den,
00111 time_base.num * (int64_t)AV_TIME_BASE,
00112 AV_ROUND_UP);
00113 max_ts = av_rescale_rnd(max_ts, time_base.den,
00114 time_base.num * (int64_t)AV_TIME_BASE,
00115 AV_ROUND_DOWN);
00116 }
00117
00118 for (i = 0; i < q->nb_subs; i++) {
00119 int64_t pts = q->subs[i].pts;
00120 uint64_t ts_diff = FFABS(pts - ts);
00121 if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
00122 min_ts_diff = ts_diff;
00123 idx = i;
00124 }
00125 }
00126 if (idx < 0)
00127 return AVERROR(ERANGE);
00128
00129 ts_selected = q->subs[idx].pts;
00130 for (i = idx - 1; i >= 0; i--) {
00131 if (q->subs[i].duration <= 0)
00132 continue;
00133 if (q->subs[i].pts > ts_selected - q->subs[i].duration)
00134 idx = i;
00135 else
00136 break;
00137 }
00138 q->current_sub_idx = idx;
00139 }
00140 return 0;
00141 }
00142
00143 void ff_subtitles_queue_clean(FFDemuxSubtitlesQueue *q)
00144 {
00145 int i;
00146
00147 for (i = 0; i < q->nb_subs; i++)
00148 av_destruct_packet(&q->subs[i]);
00149 av_freep(&q->subs);
00150 q->nb_subs = q->allocated_size = q->current_sub_idx = 0;
00151 }
00152
00153 int ff_smil_extract_next_chunk(AVIOContext *pb, AVBPrint *buf, char *c)
00154 {
00155 int i = 0;
00156 char end_chr;
00157
00158 if (!*c)
00159 *c = avio_r8(pb);
00160 if (!*c)
00161 return 0;
00162
00163 end_chr = *c == '<' ? '>' : '<';
00164 do {
00165 av_bprint_chars(buf, *c, 1);
00166 *c = avio_r8(pb);
00167 i++;
00168 } while (*c != end_chr && *c);
00169 if (end_chr == '>') {
00170 av_bprint_chars(buf, '>', 1);
00171 *c = 0;
00172 }
00173 return i;
00174 }
00175
00176 const char *ff_smil_get_attr_ptr(const char *s, const char *attr)
00177 {
00178 int in_quotes = 0;
00179 const int len = strlen(attr);
00180
00181 while (*s) {
00182 while (*s) {
00183 if (!in_quotes && isspace(*s))
00184 break;
00185 in_quotes ^= *s == '"';
00186 s++;
00187 }
00188 while (isspace(*s))
00189 s++;
00190 if (!av_strncasecmp(s, attr, len) && s[len] == '=')
00191 return s + len + 1 + (s[len + 1] == '"');
00192 }
00193 return NULL;
00194 }