📄 ffm.c
字号:
av_abort(); ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE; if (!first) break; } else { ffm->packet_ptr = ffm->packet; } goto redo; } memcpy(buf, ffm->packet_ptr, len); buf += len; ffm->packet_ptr += len; size -= len; first = 0; } return size1 - size;}static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap){ FFMContext *ffm = s->priv_data; AVStream *st; FFMStream *fst; ByteIOContext *pb = &s->pb; AVCodecContext *codec; int i, nb_streams; uint32_t tag; /* header */ tag = get_le32(pb); if (tag != MKTAG('F', 'F', 'M', '1')) goto fail; ffm->packet_size = get_be32(pb); if (ffm->packet_size != FFM_PACKET_SIZE) goto fail; ffm->write_index = get_be64(pb); /* get also filesize */ if (!url_is_streamed(pb)) { ffm->file_size = url_filesize(url_fileno(pb)); } else { ffm->file_size = (uint64_t_C(1) << 63) - 1; } nb_streams = get_be32(pb); get_be32(pb); /* total bitrate */ /* read each stream */ for(i=0;i<nb_streams;i++) { char rc_eq_buf[128]; st = av_new_stream(s, 0); if (!st) goto fail; fst = av_mallocz(sizeof(FFMStream)); if (!fst) goto fail; st->priv_data = fst; codec = &st->codec; /* generic info */ st->codec.codec_id = get_be32(pb); st->codec.codec_type = get_byte(pb); /* codec_type */ codec->bit_rate = get_be32(pb); st->quality = get_be32(pb); codec->flags = get_be32(pb); /* specific info */ switch(codec->codec_type) { case CODEC_TYPE_VIDEO: codec->frame_rate_base = get_be32(pb); codec->frame_rate = get_be32(pb); codec->width = get_be16(pb); codec->height = get_be16(pb); codec->gop_size = get_be16(pb); codec->qmin = get_byte(pb); codec->qmax = get_byte(pb); codec->max_qdiff = get_byte(pb); codec->qcompress = get_be16(pb) / 10000.0; codec->qblur = get_be16(pb) / 10000.0; codec->bit_rate_tolerance = get_be32(pb); codec->rc_eq = av_strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf))); codec->rc_max_rate = get_be32(pb); codec->rc_min_rate = get_be32(pb); codec->rc_buffer_size = get_be32(pb); codec->i_quant_factor = get_be64_double(pb); codec->b_quant_factor = get_be64_double(pb); codec->i_quant_offset = get_be64_double(pb); codec->b_quant_offset = get_be64_double(pb); codec->dct_algo = get_be32(pb); break; case CODEC_TYPE_AUDIO: codec->sample_rate = get_be32(pb); codec->channels = get_le16(pb); codec->frame_size = get_le16(pb); break; default: goto fail; } } /* get until end of block reached */ while ((url_ftell(pb) % ffm->packet_size) != 0) get_byte(pb); /* init packet demux */ ffm->packet_ptr = ffm->packet; ffm->packet_end = ffm->packet; ffm->frame_offset = 0; ffm->pts = 0; ffm->read_state = READ_HEADER; ffm->first_packet = 1; return 0; fail: for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; if (st) { av_freep(&st->priv_data); av_free(st); } } return -1;}/* return < 0 if eof */static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt){ int size; FFMContext *ffm = s->priv_data; int duration; switch(ffm->read_state) { case READ_HEADER: if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE)) { return -EAGAIN; }#if 0 printf("pos=%08Lx spos=%Lx, write_index=%Lx size=%Lx\n", url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size);#endif if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != FRAME_HEADER_SIZE) return -EAGAIN;#if 0 { int i; for(i=0;i<FRAME_HEADER_SIZE;i++) printf("%02x ", ffm->header[i]); printf("\n"); }#endif ffm->read_state = READ_DATA; /* fall thru */ case READ_DATA: size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4]; if (!ffm_is_avail_data(s, size)) { return -EAGAIN; } duration = (ffm->header[5] << 16) | (ffm->header[6] << 8) | ffm->header[7]; av_new_packet(pkt, size); pkt->stream_index = ffm->header[0]; if (ffm->header[1] & FLAG_KEY_FRAME) pkt->flags |= PKT_FLAG_KEY; ffm->read_state = READ_HEADER; if (ffm_read_data(s, pkt->data, size, 0) != size) { /* bad case: desynchronized packet. we cancel all the packet loading */ av_free_packet(pkt); return -EAGAIN; } pkt->pts = ffm->pts; pkt->duration = duration; break; } return 0;}//#define DEBUG_SEEK/* pos is between 0 and file_size - FFM_PACKET_SIZE. It is translated by the write position inside this function */static void ffm_seek1(AVFormatContext *s, offset_t pos1){ FFMContext *ffm = s->priv_data; ByteIOContext *pb = &s->pb; offset_t pos; pos = pos1 + ffm->write_index; if (pos >= ffm->file_size) pos -= (ffm->file_size - FFM_PACKET_SIZE);#ifdef DEBUG_SEEK printf("seek to %Lx -> %Lx\n", pos1, pos);#endif url_fseek(pb, pos, SEEK_SET);}static int64_t get_pts(AVFormatContext *s, offset_t pos){ ByteIOContext *pb = &s->pb; int64_t pts; ffm_seek1(s, pos); url_fskip(pb, 4); pts = get_be64(pb);#ifdef DEBUG_SEEK printf("pts=%0.6f\n", pts / 1000000.0);#endif return pts;}/* seek to a given time in the file. The file read pointer is positionned at or before pts. XXX: the following code is quite approximative */static int ffm_seek(AVFormatContext *s, int64_t wanted_pts){ FFMContext *ffm = s->priv_data; offset_t pos_min, pos_max, pos; int64_t pts_min, pts_max, pts; double pos1;#ifdef DEBUG_SEEK printf("wanted_pts=%0.6f\n", wanted_pts / 1000000.0);#endif /* find the position using linear interpolation (better than dichotomy in typical cases) */ pos_min = 0; pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; while (pos_min <= pos_max) { pts_min = get_pts(s, pos_min); pts_max = get_pts(s, pos_max); /* linear interpolation */ pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) / (double)(pts_max - pts_min); pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE; if (pos <= pos_min) pos = pos_min; else if (pos >= pos_max) pos = pos_max; pts = get_pts(s, pos); /* check if we are lucky */ if (pts == wanted_pts) { goto found; } else if (pts > wanted_pts) { pos_max = pos - FFM_PACKET_SIZE; } else { pos_min = pos + FFM_PACKET_SIZE; } } pos = pos_min; if (pos > 0) pos -= FFM_PACKET_SIZE; found: ffm_seek1(s, pos); return 0;}offset_t ffm_read_write_index(int fd){ uint8_t buf[8]; offset_t pos; int i; lseek(fd, 8, SEEK_SET); read(fd, buf, 8); pos = 0; for(i=0;i<8;i++) pos |= (int64_t)buf[i] << (56 - i * 8); return pos;}void ffm_write_write_index(int fd, offset_t pos){ uint8_t buf[8]; int i; for(i=0;i<8;i++) buf[i] = (pos >> (56 - i * 8)) & 0xff; lseek(fd, 8, SEEK_SET); write(fd, buf, 8);}void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size){ FFMContext *ffm = s->priv_data; ffm->write_index = pos; ffm->file_size = file_size;}static int ffm_read_close(AVFormatContext *s){ AVStream *st; int i; for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; av_freep(&st->priv_data); } return 0;}static int ffm_probe(AVProbeData *p){ if (p->buf_size >= 4 && p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && p->buf[3] == '1') return AVPROBE_SCORE_MAX + 1; return 0;}static AVInputFormat ffm_iformat = { "ffm", "ffm format", sizeof(FFMContext), ffm_probe, ffm_read_header, ffm_read_packet, ffm_read_close, ffm_seek,};#ifdef CONFIG_ENCODERSstatic AVOutputFormat ffm_oformat = { "ffm", "ffm format", "", "ffm", sizeof(FFMContext), /* not really used */ CODEC_ID_MP2, CODEC_ID_MPEG1VIDEO, ffm_write_header, ffm_write_packet, ffm_write_trailer,};#endif //CONFIG_ENCODERSint ffm_init(void){ av_register_input_format(&ffm_iformat);#ifdef CONFIG_ENCODERS av_register_output_format(&ffm_oformat);#endif //CONFIG_ENCODERS return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -