static int close_slave(TeeSlave *tee_slave) { AVFormatContext *avf; unsigned i; int ret = 0; avf = tee_slave->avf; if (!avf) return 0; if (tee_slave->header_written) ret = av_write_trailer(avf); if (tee_slave->bsfs) { for (i = 0; i < avf->nb_streams; ++i) av_bsf_free(&tee_slave->bsfs[i]); } av_freep(&tee_slave->stream_map); av_freep(&tee_slave->bsfs); ff_format_io_close(avf, &avf->pb); avformat_free_context(avf); tee_slave->avf = NULL; return ret; }
static int seg_write_trailer(struct AVFormatContext *s) { SegmentContext *seg = s->priv_data; AVFormatContext *oc = seg->avf; int ret = 0; if (!oc) goto fail; if (!seg->write_header_trailer) { if ((ret = segment_end(oc, 0)) < 0) goto fail; if ((ret = open_null_ctx(&oc->pb)) < 0) goto fail; ret = av_write_trailer(oc); close_null_ctx(oc->pb); } else { ret = segment_end(oc, 1); } if (ret < 0) goto fail; if (seg->list && seg->list_type == LIST_HLS) { if ((ret = segment_hls_window(s, 1) < 0)) goto fail; } fail: ff_format_io_close(s, &seg->pb); avformat_free_context(oc); return ret; }
static int close_slave(TeeSlave *tee_slave) { AVFormatContext *avf; unsigned i; int ret = 0; avf = tee_slave->avf; if (!avf) return 0; if (tee_slave->header_written) ret = av_write_trailer(avf); if (tee_slave->bsfs) { for (i = 0; i < avf->nb_streams; ++i) { AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i]; while (bsf) { bsf_next = bsf->next; av_bitstream_filter_close(bsf); bsf = bsf_next; } } } av_freep(&tee_slave->stream_map); av_freep(&tee_slave->bsfs); ff_format_io_close(avf, &avf->pb); avformat_free_context(avf); tee_slave->avf = NULL; return ret; }
static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) { SegmentContext *seg = s->priv_data; AVFormatContext *oc = seg->avf; AVStream *st = s->streams[pkt->stream_index]; int64_t end_pts = seg->recording_time * seg->number; int ret, can_split = 1; if (!oc) return AVERROR(EINVAL); if (seg->has_video) { can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pkt->flags & AV_PKT_FLAG_KEY; } if (can_split && av_compare_ts(pkt->pts, st->time_base, end_pts, AV_TIME_BASE_Q) >= 0) { av_log(s, AV_LOG_DEBUG, "Next segment starts at %d %"PRId64"\n", pkt->stream_index, pkt->pts); ret = segment_end(oc, seg->individual_header_trailer); if (!ret) ret = segment_start(s, seg->individual_header_trailer); if (ret) goto fail; oc = seg->avf; if (seg->list) { if (seg->list_type == LIST_HLS) { if ((ret = segment_hls_window(s, 0)) < 0) goto fail; } else { avio_printf(seg->pb, "%s\n", oc->filename); avio_flush(seg->pb); if (seg->size && !(seg->number % seg->size)) { ff_format_io_close(s, &seg->pb); if ((ret = s->io_open(s, &seg->pb, seg->list, AVIO_FLAG_WRITE, NULL)) < 0) goto fail; } } } } ret = ff_write_chained(oc, pkt->stream_index, pkt, s); fail: if (ret < 0) seg_free_context(seg); return ret; }
static int segment_end(AVFormatContext *oc, int write_trailer) { int ret = 0; av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */ if (write_trailer) av_write_trailer(oc); ff_format_io_close(oc, &oc->pb); return ret; }
static int segment_hls_window(AVFormatContext *s, int last) { SegmentContext *seg = s->priv_data; int i, ret = 0; char buf[1024]; if ((ret = s->io_open(s, &seg->pb, seg->list, AVIO_FLAG_WRITE, NULL)) < 0) goto fail; avio_printf(seg->pb, "#EXTM3U\n"); avio_printf(seg->pb, "#EXT-X-VERSION:3\n"); avio_printf(seg->pb, "#EXT-X-TARGETDURATION:%d\n", (int)seg->time); avio_printf(seg->pb, "#EXT-X-MEDIA-SEQUENCE:%d\n", FFMAX(0, seg->number - seg->size)); av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%d\n", FFMAX(0, seg->number - seg->size)); for (i = FFMAX(0, seg->number - seg->size); i < seg->number; i++) { avio_printf(seg->pb, "#EXTINF:%d,\n", (int)seg->time); if (seg->entry_prefix) { avio_printf(seg->pb, "%s", seg->entry_prefix); } ret = av_get_frame_filename(buf, sizeof(buf), s->filename, i); if (ret < 0) { ret = AVERROR(EINVAL); goto fail; } avio_printf(seg->pb, "%s\n", buf); } if (last) avio_printf(seg->pb, "#EXT-X-ENDLIST\n"); fail: ff_format_io_close(s, &seg->pb); return ret; }
int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt) { VideoDemuxData *s = s1->priv_data; char filename_bytes[1024]; char *filename = filename_bytes; int i, res; int size[3] = { 0 }, ret[3] = { 0 }; AVIOContext *f[3] = { NULL }; AVCodecParameters *par = s1->streams[0]->codecpar; if (!s->is_pipe) { /* loop over input */ if (s->loop && s->img_number > s->img_last) { s->img_number = s->img_first; } if (s->img_number > s->img_last) return AVERROR_EOF; if (s->pattern_type == PT_NONE) { av_strlcpy(filename_bytes, s->path, sizeof(filename_bytes)); } else if (s->use_glob) { #if HAVE_GLOB filename = s->globstate.gl_pathv[s->img_number]; #endif } else { if (av_get_frame_filename(filename_bytes, sizeof(filename_bytes), s->path, s->img_number) < 0 && s->img_number > 1) return AVERROR(EIO); } for (i = 0; i < 3; i++) { if (s1->pb && !strcmp(filename_bytes, s->path) && !s->loop && !s->split_planes) { f[i] = s1->pb; } else if (s1->io_open(s1, &f[i], filename, AVIO_FLAG_READ, NULL) < 0) { if (i >= 1) break; av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n", filename); return AVERROR(EIO); } size[i] = avio_size(f[i]); if (!s->split_planes) break; filename[strlen(filename) - 1] = 'U' + i; } if (par->codec_id == AV_CODEC_ID_NONE) { AVProbeData pd = { 0 }; AVInputFormat *ifmt; uint8_t header[PROBE_BUF_MIN + AVPROBE_PADDING_SIZE]; int ret; int score = 0; ret = avio_read(f[0], header, PROBE_BUF_MIN); if (ret < 0) return ret; memset(header + ret, 0, sizeof(header) - ret); avio_skip(f[0], -ret); pd.buf = header; pd.buf_size = ret; pd.filename = filename; ifmt = av_probe_input_format3(&pd, 1, &score); if (ifmt && ifmt->read_packet == ff_img_read_packet && ifmt->raw_codec_id) par->codec_id = ifmt->raw_codec_id; } if (par->codec_id == AV_CODEC_ID_RAWVIDEO && !par->width) infer_size(&par->width, &par->height, size[0]); } else { f[0] = s1->pb; if (avio_feof(f[0]) && s->loop && s->is_pipe) avio_seek(f[0], 0, SEEK_SET); if (avio_feof(f[0])) return AVERROR_EOF; if (s->frame_size > 0) { size[0] = s->frame_size; } else if (!s1->streams[0]->parser) { size[0] = avio_size(s1->pb); } else { size[0] = 4096; } } res = av_new_packet(pkt, size[0] + size[1] + size[2]); if (res < 0) { goto fail; } pkt->stream_index = 0; pkt->flags |= AV_PKT_FLAG_KEY; if (s->ts_from_file) { struct stat img_stat; if (stat(filename, &img_stat)) { res = AVERROR(EIO); goto fail; } pkt->pts = (int64_t)img_stat.st_mtime; #if HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC if (s->ts_from_file == 2) pkt->pts = 1000000000*pkt->pts + img_stat.st_mtim.tv_nsec; #endif av_add_index_entry(s1->streams[0], s->img_number, pkt->pts, 0, 0, AVINDEX_KEYFRAME); } else if (!s->is_pipe) { pkt->pts = s->pts; } if (s->is_pipe) pkt->pos = avio_tell(f[0]); pkt->size = 0; for (i = 0; i < 3; i++) { if (f[i]) { ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]); if (s->loop && s->is_pipe && ret[i] == AVERROR_EOF) { if (avio_seek(f[i], 0, SEEK_SET) >= 0) { pkt->pos = 0; ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]); } } if (!s->is_pipe && f[i] != s1->pb) ff_format_io_close(s1, &f[i]); if (ret[i] > 0) pkt->size += ret[i]; } } if (ret[0] <= 0 || ret[1] < 0 || ret[2] < 0) { av_packet_unref(pkt); if (ret[0] < 0) { res = ret[0]; } else if (ret[1] < 0) { res = ret[1]; } else if (ret[2] < 0) { res = ret[2]; } else { res = AVERROR_EOF; } goto fail; } else { s->img_count++; s->img_number++; s->pts++; return 0; } fail: if (!s->is_pipe) { for (i = 0; i < 3; i++) { if (f[i] != s1->pb) ff_format_io_close(s1, &f[i]); } } return res; }
static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) { VideoDemuxData *s = s1->priv_data; char filename[1024]; int i, res; int size[3] = { 0 }, ret[3] = { 0 }; AVIOContext *f[3] = { NULL }; AVCodecContext *codec = s1->streams[0]->codec; if (!s->is_pipe) { /* loop over input */ if (s->loop && s->img_number > s->img_last) { s->img_number = s->img_first; } if (s->img_number > s->img_last) return AVERROR_EOF; if (av_get_frame_filename(filename, sizeof(filename), s->path, s->img_number) < 0 && s->img_number > 1) return AVERROR(EIO); for (i = 0; i < 3; i++) { if (s1->io_open(s1, &f[i], filename, AVIO_FLAG_READ, NULL) < 0) { if (i >= 1) break; av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n", filename); return AVERROR(EIO); } size[i] = avio_size(f[i]); if (codec->codec_id != AV_CODEC_ID_RAWVIDEO) break; filename[strlen(filename) - 1] = 'U' + i; } if (codec->codec_id == AV_CODEC_ID_RAWVIDEO && !codec->width) infer_size(&codec->width, &codec->height, size[0]); } else { f[0] = s1->pb; if (f[0]->eof_reached) return AVERROR(EIO); size[0] = 4096; } res = av_new_packet(pkt, size[0] + size[1] + size[2]); if (res < 0) return res; pkt->stream_index = 0; pkt->flags |= AV_PKT_FLAG_KEY; pkt->size = 0; for (i = 0; i < 3; i++) { if (f[i]) { ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]); if (!s->is_pipe) ff_format_io_close(s1, &f[i]); if (ret[i] > 0) pkt->size += ret[i]; } } if (ret[0] <= 0 || ret[1] < 0 || ret[2] < 0) { av_packet_unref(pkt); return AVERROR(EIO); /* signal EOF */ } else { s->img_count++; s->img_number++; return 0; } }
static int write_packet(AVFormatContext *s, AVPacket *pkt) { VideoMuxData *img = s->priv_data; AVIOContext *pb[4]; char filename[1024]; AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(par->format); int i; int nb_renames = 0; if (!img->is_pipe) { if (img->update) { av_strlcpy(filename, img->path, sizeof(filename)); } else if (img->use_strftime) { time_t now0; struct tm *tm, tmpbuf; time(&now0); tm = localtime_r(&now0, &tmpbuf); if (!strftime(filename, sizeof(filename), img->path, tm)) { av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n"); return AVERROR(EINVAL); } } else if (av_get_frame_filename2(filename, sizeof(filename), img->path, img->img_number, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0 && img->img_number > 1) { av_log(s, AV_LOG_ERROR, "Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n", img->img_number, img->path); return AVERROR(EINVAL); } for (i = 0; i < 4; i++) { snprintf(img->tmp[i], sizeof(img->tmp[i]), "%s.tmp", filename); av_strlcpy(img->target[i], filename, sizeof(img->target[i])); if (s->io_open(s, &pb[i], img->use_rename ? img->tmp[i] : filename, AVIO_FLAG_WRITE, NULL) < 0) { av_log(s, AV_LOG_ERROR, "Could not open file : %s\n", img->use_rename ? img->tmp[i] : filename); return AVERROR(EIO); } if (!img->split_planes || i+1 >= desc->nb_components) break; filename[strlen(filename) - 1] = "UVAx"[i]; } if (img->use_rename) nb_renames = i + 1; } else { pb[0] = s->pb; } if (img->split_planes) { int ysize = par->width * par->height; int usize = AV_CEIL_RSHIFT(par->width, desc->log2_chroma_w) * AV_CEIL_RSHIFT(par->height, desc->log2_chroma_h); if (desc->comp[0].depth >= 9) { ysize *= 2; usize *= 2; } avio_write(pb[0], pkt->data , ysize); avio_write(pb[1], pkt->data + ysize , usize); avio_write(pb[2], pkt->data + ysize + usize, usize); ff_format_io_close(s, &pb[1]); ff_format_io_close(s, &pb[2]); if (desc->nb_components > 3) { avio_write(pb[3], pkt->data + ysize + 2*usize, ysize); ff_format_io_close(s, &pb[3]); } } else if (img->muxer) { int ret; AVStream *st; AVPacket pkt2 = {0}; AVFormatContext *fmt = NULL; av_assert0(!img->split_planes); ret = avformat_alloc_output_context2(&fmt, NULL, img->muxer, s->filename); if (ret < 0) return ret; st = avformat_new_stream(fmt, NULL); if (!st) { avformat_free_context(fmt); return AVERROR(ENOMEM); } st->id = pkt->stream_index; fmt->pb = pb[0]; if ((ret = av_copy_packet(&pkt2, pkt)) < 0 || (ret = av_dup_packet(&pkt2)) < 0 || (ret = avcodec_parameters_copy(st->codecpar, s->streams[0]->codecpar)) < 0 || (ret = avformat_write_header(fmt, NULL)) < 0 || (ret = av_interleaved_write_frame(fmt, &pkt2)) < 0 || (ret = av_write_trailer(fmt)) < 0) { av_packet_unref(&pkt2); avformat_free_context(fmt); return ret; } av_packet_unref(&pkt2); avformat_free_context(fmt); } else { avio_write(pb[0], pkt->data, pkt->size); } avio_flush(pb[0]); if (!img->is_pipe) { ff_format_io_close(s, &pb[0]); for (i = 0; i < nb_renames; i++) { int ret = ff_rename(img->tmp[i], img->target[i], s); if (ret < 0) return ret; } } img->img_number++; return 0; }
static int shift_data(AVFormatContext *s) { int ret = 0; int n = 0; int64_t metadata_size = 0; FLVContext *flv = s->priv_data; int64_t pos, pos_end = avio_tell(s->pb); uint8_t *buf, *read_buf[2]; int read_buf_id = 0; int read_size[2]; AVIOContext *read_pb; metadata_size = flv->filepositions_count * 9 * 2 + 10; /* filepositions and times value */ metadata_size += 2 + 13; /* filepositions String */ metadata_size += 2 + 5; /* times String */ metadata_size += 3; /* Object end */ flv->keyframe_index_size = metadata_size; if (metadata_size < 0) return metadata_size; buf = av_malloc_array(metadata_size, 2); if (!buf) { return AVERROR(ENOMEM); } read_buf[0] = buf; read_buf[1] = buf + metadata_size; avio_seek(s->pb, flv->metadata_size_pos, SEEK_SET); avio_wb24(s->pb, flv->metadata_totalsize + metadata_size); avio_seek(s->pb, flv->metadata_totalsize_pos, SEEK_SET); avio_wb32(s->pb, flv->metadata_totalsize + 11 + metadata_size); avio_seek(s->pb, pos_end, SEEK_SET); /* Shift the data: the AVIO context of the output can only be used for * writing, so we re-open the same output, but for reading. It also avoids * a read/seek/write/seek back and forth. */ avio_flush(s->pb); ret = s->io_open(s, &read_pb, s->filename, AVIO_FLAG_READ, NULL); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for " "the second pass (add_keyframe_index)\n", s->filename); goto end; } /* mark the end of the shift to up to the last data we wrote, and get ready * for writing */ pos_end = avio_tell(s->pb); avio_seek(s->pb, flv->keyframes_info_offset + metadata_size, SEEK_SET); /* start reading at where the keyframe index information will be placed */ avio_seek(read_pb, flv->keyframes_info_offset, SEEK_SET); pos = avio_tell(read_pb); /* shift data by chunk of at most keyframe *filepositions* and *times* size */ read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], metadata_size); \ read_buf_id ^= 1; do { read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], metadata_size); \ read_buf_id ^= 1; n = read_size[read_buf_id]; if (n < 0) break; avio_write(s->pb, read_buf[read_buf_id], n); pos += n; } while (pos <= pos_end); ff_format_io_close(s, &read_pb); end: av_free(buf); return ret; }
static int seg_write_header(AVFormatContext *s) { SegmentContext *seg = s->priv_data; AVFormatContext *oc = NULL; int ret, i; seg->number = 0; seg->offset_time = 0; seg->recording_time = seg->time * 1000000; if (!seg->write_header_trailer) seg->individual_header_trailer = 0; if (seg->list && seg->list_type != LIST_HLS) if ((ret = s->io_open(s, &seg->pb, seg->list, AVIO_FLAG_WRITE, NULL)) < 0) goto fail; for (i = 0; i < s->nb_streams; i++) seg->has_video += (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO); if (seg->has_video > 1) av_log(s, AV_LOG_WARNING, "More than a single video stream present, " "expect issues decoding it.\n"); seg->oformat = av_guess_format(seg->format, s->filename, NULL); if (!seg->oformat) { ret = AVERROR_MUXER_NOT_FOUND; goto fail; } if (seg->oformat->flags & AVFMT_NOFILE) { av_log(s, AV_LOG_ERROR, "format %s not supported.\n", seg->oformat->name); ret = AVERROR(EINVAL); goto fail; } if ((ret = segment_mux_init(s)) < 0) goto fail; oc = seg->avf; if (av_get_frame_filename(oc->filename, sizeof(oc->filename), s->filename, seg->number++) < 0) { ret = AVERROR(EINVAL); goto fail; } if (seg->write_header_trailer) { if ((ret = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0) goto fail; } else { if ((ret = open_null_ctx(&oc->pb)) < 0) goto fail; } if ((ret = avformat_write_header(oc, NULL)) < 0) { ff_format_io_close(oc, &oc->pb); goto fail; } if (!seg->write_header_trailer) { close_null_ctx(oc->pb); if ((ret = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0) goto fail; } if (seg->list) { if (seg->list_type == LIST_HLS) { if ((ret = segment_hls_window(s, 0)) < 0) goto fail; } else { avio_printf(seg->pb, "%s\n", oc->filename); avio_flush(seg->pb); } } fail: if (ret < 0) seg_free_context(seg); return ret; }
static void seg_free_context(SegmentContext *seg) { ff_format_io_close(seg->avf, &seg->pb); avformat_free_context(seg->avf); seg->avf = NULL; }