ffmdec.c

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

Generated on Fri Jan 9 14:44:28 2009 for libextractor by  doxygen 1.5.1