00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/intreadwrite.h"
00023 #include "avformat.h"
00024 #include "ffm.h"
00025 #if CONFIG_FFSERVER
00026 #include <unistd.h>
00027
00028 int64_t ffm_read_write_index(int fd)
00029 {
00030 uint8_t buf[8];
00031
00032 lseek(fd, 8, SEEK_SET);
00033 if (read(fd, buf, 8) != 8)
00034 return AVERROR(EIO);
00035 return AV_RB64(buf);
00036 }
00037
00038 int ffm_write_write_index(int fd, int64_t pos)
00039 {
00040 uint8_t buf[8];
00041 int i;
00042
00043 for(i=0;i<8;i++)
00044 buf[i] = (pos >> (56 - i * 8)) & 0xff;
00045 lseek(fd, 8, SEEK_SET);
00046 if (write(fd, buf, 8) != 8)
00047 return AVERROR(EIO);
00048 return 8;
00049 }
00050
00051 void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size)
00052 {
00053 FFMContext *ffm = s->priv_data;
00054 ffm->write_index = pos;
00055 ffm->file_size = file_size;
00056 }
00057 #endif // CONFIG_FFSERVER
00058
00059 static int ffm_is_avail_data(AVFormatContext *s, int size)
00060 {
00061 FFMContext *ffm = s->priv_data;
00062 int64_t pos, avail_size;
00063 int len;
00064
00065 len = ffm->packet_end - ffm->packet_ptr;
00066 if (size <= len)
00067 return 1;
00068 pos = url_ftell(s->pb);
00069 if (pos == ffm->write_index) {
00070
00071 return 0;
00072 } else if (pos < ffm->write_index) {
00073 avail_size = ffm->write_index - pos;
00074 } else {
00075 avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
00076 }
00077 avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
00078 if (size <= avail_size)
00079 return 1;
00080 else
00081 return 0;
00082 }
00083
00084
00085 static int ffm_read_data(AVFormatContext *s,
00086 uint8_t *buf, int size, int header)
00087 {
00088 FFMContext *ffm = s->priv_data;
00089 ByteIOContext *pb = s->pb;
00090 int len, fill_size, size1, frame_offset;
00091
00092 size1 = size;
00093 while (size > 0) {
00094 redo:
00095 len = ffm->packet_end - ffm->packet_ptr;
00096 if (len < 0)
00097 return -1;
00098 if (len > size)
00099 len = size;
00100 if (len == 0) {
00101 if (url_ftell(pb) == ffm->file_size)
00102 url_fseek(pb, ffm->packet_size, SEEK_SET);
00103 retry_read:
00104 get_be16(pb);
00105 fill_size = get_be16(pb);
00106 ffm->dts = get_be64(pb);
00107 frame_offset = get_be16(pb);
00108 get_buffer(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
00109 ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
00110 if (ffm->packet_end < ffm->packet || frame_offset < 0)
00111 return -1;
00112
00113
00114 if (ffm->first_packet || (frame_offset & 0x8000)) {
00115 if (!frame_offset) {
00116
00117 if (url_ftell(pb) >= ffm->packet_size * 3) {
00118 url_fseek(pb, -ffm->packet_size * 2, SEEK_CUR);
00119 goto retry_read;
00120 }
00121
00122 return 0;
00123 }
00124 ffm->first_packet = 0;
00125 if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE)
00126 return -1;
00127 ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
00128 if (!header)
00129 break;
00130 } else {
00131 ffm->packet_ptr = ffm->packet;
00132 }
00133 goto redo;
00134 }
00135 memcpy(buf, ffm->packet_ptr, len);
00136 buf += len;
00137 ffm->packet_ptr += len;
00138 size -= len;
00139 header = 0;
00140 }
00141 return size1 - size;
00142 }
00143
00144
00145
00146
00147
00148 static void ffm_seek1(AVFormatContext *s, int64_t pos1)
00149 {
00150 FFMContext *ffm = s->priv_data;
00151 ByteIOContext *pb = s->pb;
00152 int64_t pos;
00153
00154 pos = pos1 + ffm->write_index;
00155 if (pos >= ffm->file_size)
00156 pos -= (ffm->file_size - FFM_PACKET_SIZE);
00157 #ifdef DEBUG_SEEK
00158 av_log(s, AV_LOG_DEBUG, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos);
00159 #endif
00160 url_fseek(pb, pos, SEEK_SET);
00161 }
00162
00163 static int64_t get_dts(AVFormatContext *s, int64_t pos)
00164 {
00165 ByteIOContext *pb = s->pb;
00166 int64_t dts;
00167
00168 ffm_seek1(s, pos);
00169 url_fskip(pb, 4);
00170 dts = get_be64(pb);
00171 #ifdef DEBUG_SEEK
00172 av_log(s, AV_LOG_DEBUG, "pts=%0.6f\n", pts / 1000000.0);
00173 #endif
00174 return dts;
00175 }
00176
00177 static void adjust_write_index(AVFormatContext *s)
00178 {
00179 FFMContext *ffm = s->priv_data;
00180 ByteIOContext *pb = s->pb;
00181 int64_t pts;
00182
00183 int64_t pos_min, pos_max;
00184 int64_t pts_start;
00185 int64_t ptr = url_ftell(pb);
00186
00187
00188 pos_min = 0;
00189 pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
00190
00191 pts_start = get_dts(s, pos_min);
00192
00193 pts = get_dts(s, pos_max);
00194
00195 if (pts - 100000 > pts_start)
00196 goto end;
00197
00198 ffm->write_index = FFM_PACKET_SIZE;
00199
00200 pts_start = get_dts(s, pos_min);
00201
00202 pts = get_dts(s, pos_max);
00203
00204 if (pts - 100000 <= pts_start) {
00205 while (1) {
00206 int64_t newpos;
00207 int64_t newpts;
00208
00209 newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE;
00210
00211 if (newpos == pos_min)
00212 break;
00213
00214 newpts = get_dts(s, newpos);
00215
00216 if (newpts - 100000 <= pts) {
00217 pos_max = newpos;
00218 pts = newpts;
00219 } else {
00220 pos_min = newpos;
00221 }
00222 }
00223 ffm->write_index += pos_max;
00224 }
00225
00226
00227
00228
00229 end:
00230 url_fseek(pb, ptr, SEEK_SET);
00231 }
00232
00233
00234 static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
00235 {
00236 FFMContext *ffm = s->priv_data;
00237 AVStream *st;
00238 ByteIOContext *pb = s->pb;
00239 AVCodecContext *codec;
00240 int i, nb_streams;
00241 uint32_t tag;
00242
00243
00244 tag = get_le32(pb);
00245 if (tag != MKTAG('F', 'F', 'M', '1'))
00246 goto fail;
00247 ffm->packet_size = get_be32(pb);
00248 if (ffm->packet_size != FFM_PACKET_SIZE)
00249 goto fail;
00250 ffm->write_index = get_be64(pb);
00251
00252 if (!url_is_streamed(pb)) {
00253 ffm->file_size = url_fsize(pb);
00254 adjust_write_index(s);
00255 } else {
00256 ffm->file_size = (UINT64_C(1) << 63) - 1;
00257 }
00258
00259 nb_streams = get_be32(pb);
00260 get_be32(pb);
00261
00262 for(i=0;i<nb_streams;i++) {
00263 char rc_eq_buf[128];
00264
00265 st = av_new_stream(s, 0);
00266 if (!st)
00267 goto fail;
00268 s->streams[i] = st;
00269
00270 av_set_pts_info(st, 64, 1, 1000000);
00271
00272 codec = st->codec;
00273
00274 codec->codec_id = get_be32(pb);
00275 codec->codec_type = get_byte(pb);
00276 codec->bit_rate = get_be32(pb);
00277 st->quality = get_be32(pb);
00278 codec->flags = get_be32(pb);
00279 codec->flags2 = get_be32(pb);
00280 codec->debug = get_be32(pb);
00281
00282 switch(codec->codec_type) {
00283 case CODEC_TYPE_VIDEO:
00284 codec->time_base.num = get_be32(pb);
00285 codec->time_base.den = get_be32(pb);
00286 codec->width = get_be16(pb);
00287 codec->height = get_be16(pb);
00288 codec->gop_size = get_be16(pb);
00289 codec->pix_fmt = get_be32(pb);
00290 codec->qmin = get_byte(pb);
00291 codec->qmax = get_byte(pb);
00292 codec->max_qdiff = get_byte(pb);
00293 codec->qcompress = get_be16(pb) / 10000.0;
00294 codec->qblur = get_be16(pb) / 10000.0;
00295 codec->bit_rate_tolerance = get_be32(pb);
00296 codec->rc_eq = av_strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf)));
00297 codec->rc_max_rate = get_be32(pb);
00298 codec->rc_min_rate = get_be32(pb);
00299 codec->rc_buffer_size = get_be32(pb);
00300 codec->i_quant_factor = av_int2dbl(get_be64(pb));
00301 codec->b_quant_factor = av_int2dbl(get_be64(pb));
00302 codec->i_quant_offset = av_int2dbl(get_be64(pb));
00303 codec->b_quant_offset = av_int2dbl(get_be64(pb));
00304 codec->dct_algo = get_be32(pb);
00305 codec->strict_std_compliance = get_be32(pb);
00306 codec->max_b_frames = get_be32(pb);
00307 codec->luma_elim_threshold = get_be32(pb);
00308 codec->chroma_elim_threshold = get_be32(pb);
00309 codec->mpeg_quant = get_be32(pb);
00310 codec->intra_dc_precision = get_be32(pb);
00311 codec->me_method = get_be32(pb);
00312 codec->mb_decision = get_be32(pb);
00313 codec->nsse_weight = get_be32(pb);
00314 codec->frame_skip_cmp = get_be32(pb);
00315 codec->rc_buffer_aggressivity = av_int2dbl(get_be64(pb));
00316 codec->codec_tag = get_be32(pb);
00317 codec->thread_count = get_byte(pb);
00318 break;
00319 case CODEC_TYPE_AUDIO:
00320 codec->sample_rate = get_be32(pb);
00321 codec->channels = get_le16(pb);
00322 codec->frame_size = get_le16(pb);
00323 break;
00324 default:
00325 goto fail;
00326 }
00327 if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
00328 codec->extradata_size = get_be32(pb);
00329 codec->extradata = av_malloc(codec->extradata_size);
00330 if (!codec->extradata)
00331 return AVERROR(ENOMEM);
00332 get_buffer(pb, codec->extradata, codec->extradata_size);
00333 }
00334 }
00335
00336
00337 while ((url_ftell(pb) % ffm->packet_size) != 0)
00338 get_byte(pb);
00339
00340
00341 ffm->packet_ptr = ffm->packet;
00342 ffm->packet_end = ffm->packet;
00343 ffm->frame_offset = 0;
00344 ffm->dts = 0;
00345 ffm->read_state = READ_HEADER;
00346 ffm->first_packet = 1;
00347 return 0;
00348 fail:
00349 for(i=0;i<s->nb_streams;i++) {
00350 st = s->streams[i];
00351 if (st) {
00352 av_free(st);
00353 }
00354 }
00355 return -1;
00356 }
00357
00358
00359 static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
00360 {
00361 int size;
00362 FFMContext *ffm = s->priv_data;
00363 int duration;
00364
00365 if (url_fsize(s->pb) == FFM_PACKET_SIZE)
00366 return -1;
00367
00368 switch(ffm->read_state) {
00369 case READ_HEADER:
00370 if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) {
00371 return AVERROR(EAGAIN);
00372 }
00373 dprintf(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n",
00374 url_ftell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size);
00375 if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) !=
00376 FRAME_HEADER_SIZE)
00377 return AVERROR(EAGAIN);
00378 if (ffm->header[1] & FLAG_DTS)
00379 if (ffm_read_data(s, ffm->header+16, 4, 1) != 4)
00380 return AVERROR(EAGAIN);
00381 #if 0
00382 av_hexdump_log(s, AV_LOG_DEBUG, ffm->header, FRAME_HEADER_SIZE);
00383 #endif
00384 ffm->read_state = READ_DATA;
00385
00386 case READ_DATA:
00387 size = AV_RB24(ffm->header + 2);
00388 if (!ffm_is_avail_data(s, size)) {
00389 return AVERROR(EAGAIN);
00390 }
00391
00392 duration = AV_RB24(ffm->header + 5);
00393
00394 av_new_packet(pkt, size);
00395 pkt->stream_index = ffm->header[0];
00396 if ((unsigned)pkt->stream_index >= s->nb_streams) {
00397 av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index);
00398 av_free_packet(pkt);
00399 ffm->read_state = READ_HEADER;
00400 return AVERROR(EAGAIN);
00401 }
00402 pkt->pos = url_ftell(s->pb);
00403 if (ffm->header[1] & FLAG_KEY_FRAME)
00404 pkt->flags |= PKT_FLAG_KEY;
00405
00406 ffm->read_state = READ_HEADER;
00407 if (ffm_read_data(s, pkt->data, size, 0) != size) {
00408
00409 av_free_packet(pkt);
00410 return AVERROR(EAGAIN);
00411 }
00412 pkt->pts = AV_RB64(ffm->header+8);
00413 if (ffm->header[1] & FLAG_DTS)
00414 pkt->dts = pkt->pts - AV_RB32(ffm->header+16);
00415 else
00416 pkt->dts = pkt->pts;
00417 pkt->duration = duration;
00418 break;
00419 }
00420 return 0;
00421 }
00422
00423
00424
00425
00426 static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags)
00427 {
00428 FFMContext *ffm = s->priv_data;
00429 int64_t pos_min, pos_max, pos;
00430 int64_t pts_min, pts_max, pts;
00431 double pos1;
00432
00433 #ifdef DEBUG_SEEK
00434 av_log(s, AV_LOG_DEBUG, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
00435 #endif
00436
00437
00438 pos_min = 0;
00439 pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
00440 while (pos_min <= pos_max) {
00441 pts_min = get_dts(s, pos_min);
00442 pts_max = get_dts(s, pos_max);
00443
00444 pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
00445 (double)(pts_max - pts_min);
00446 pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
00447 if (pos <= pos_min)
00448 pos = pos_min;
00449 else if (pos >= pos_max)
00450 pos = pos_max;
00451 pts = get_dts(s, pos);
00452
00453 if (pts == wanted_pts) {
00454 goto found;
00455 } else if (pts > wanted_pts) {
00456 pos_max = pos - FFM_PACKET_SIZE;
00457 } else {
00458 pos_min = pos + FFM_PACKET_SIZE;
00459 }
00460 }
00461 pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
00462 if (pos > 0)
00463 pos -= FFM_PACKET_SIZE;
00464 found:
00465 ffm_seek1(s, pos);
00466
00467
00468 ffm->read_state = READ_HEADER;
00469 ffm->packet_ptr = ffm->packet;
00470 ffm->packet_end = ffm->packet;
00471 ffm->first_packet = 1;
00472
00473 return 0;
00474 }
00475
00476 static int ffm_probe(AVProbeData *p)
00477 {
00478 if (
00479 p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
00480 p->buf[3] == '1')
00481 return AVPROBE_SCORE_MAX + 1;
00482 return 0;
00483 }
00484
00485 AVInputFormat ffm_demuxer = {
00486 "ffm",
00487 NULL_IF_CONFIG_SMALL("FFM (FFserver live feed) format"),
00488 sizeof(FFMContext),
00489 ffm_probe,
00490 ffm_read_header,
00491 ffm_read_packet,
00492 NULL,
00493 ffm_seek,
00494 };