You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.3 KiB

#include <stdio.h>
#include "segment.h"
#include <pthread.h>
#include <libavutil/opt.h>
void save_segment(struct Segment *seg, const char *filename)
{
FILE *out = fopen(filename, "w");
fwrite(seg->buf, seg->size, 1, out);
fclose(out);
}
void segment_free(struct Segment *seg)
{
printf("Freeing segment\n");
avformat_free_context(seg->fmt_ctx);
av_free(seg->io_ctx->buffer);
av_free(seg->io_ctx);
free(seg->buf);
free(seg->ts);
free(seg);
}
void segment_ref(struct Segment *seg)
{
pthread_mutex_lock(&seg->nb_read_lock);
seg->nb_read++;
printf(" ref Readers: %d\n", seg->nb_read);
pthread_mutex_unlock(&seg->nb_read_lock);
}
void segment_unref(struct Segment *seg)
{
pthread_mutex_lock(&seg->nb_read_lock);
seg->nb_read--;
pthread_mutex_unlock(&seg->nb_read_lock);
printf("unref Readers: %d\n", seg->nb_read);
if (seg->nb_read == 0) {
segment_free(seg);
}
}
void segment_ts_append(struct Segment *seg, int64_t dts, int64_t pts)
{
seg->ts = (int64_t*) realloc(seg->ts, sizeof(int64_t) * 2 * (seg->ts_len + 2));
seg->ts[seg->ts_len] = dts;
seg->ts[seg->ts_len + 1] = pts;
seg->ts_len += 2;
return;
}
int segment_write(void *opaque, unsigned char *buf, int buf_size)
{
struct Segment *seg = (struct Segment*) opaque;
//return fwrite(buf, buf_size, 1, seg->stream);
seg->size += buf_size;
seg->buf = (char*) realloc(seg->buf, seg->size);
//printf("buf:%p size:%zu\n", seg->buf, seg->size);
memcpy(seg->buf + seg->size - buf_size, buf, buf_size);
return buf_size;
}
/*int segment_read(void *opaque, unsigned char *buf, int buf_size)
{
struct Segment *seg = (struct Segment*) opaque;
return fread(buf, buf_size, 1, seg->stream);
} */
int segment_read(void *opaque, unsigned char *buf, int buf_size)
{
struct AVIOContextInfo *info = (struct AVIOContextInfo*) opaque;
buf_size = buf_size < info->left ? buf_size : info->left;
//printf("buf:%p left:%d\n", info->buf, info->left);
/* copy internal buffer data to buf */
memcpy(buf, info->buf, buf_size);
info->buf += buf_size;
info->left -= buf_size;
return buf_size ? buf_size : AVERROR_EOF;
}
/*int64_t segment_seek(void *opaque, int64_t offset, int whence)
{
struct Segment *seg = (struct Segment*) opaque;
return fseek(seg->stream, offset, whence);
}
*/
void segment_close(struct Segment *seg)
{
//avio_flush(seg->io_ctx);
av_write_trailer(seg->fmt_ctx);
/* if (seg->io_ctx)
avio_close(seg->io_ctx);
*/
//fclose(seg->stream);
}
void segment_init(struct Segment **seg_p, AVFormatContext *fmt)
{
int ret;
size_t i;
AVStream *in_stream, *out_stream;
AVCodecContext *codec_ctx;
struct Segment *seg = (struct Segment*) malloc(sizeof(struct Segment));
seg->ifmt = fmt->iformat;
seg->fmt_ctx = NULL;
seg->nb_read = 0;
seg->size = 0;
seg->ts = NULL;
seg->ts_len = 0;
seg->buf = NULL;
seg->avio_buffer = (unsigned char*) av_malloc(AV_BUFSIZE);
pthread_mutex_init(&seg->nb_read_lock, NULL);
//(*seg)->stream = open_memstream(&(*seg)->buf, &(*seg)->size);
seg->io_ctx = avio_alloc_context(seg->avio_buffer, AV_BUFSIZE, 1, seg, NULL, &segment_write, NULL);
seg->io_ctx->seekable = 0;
avformat_alloc_output_context2(&seg->fmt_ctx, NULL, "matroska", NULL);
if ((ret = av_opt_set_int(seg->fmt_ctx, "flush_packets", 1, AV_OPT_SEARCH_CHILDREN)) < 0) {
printf("Could not set flush_packets!\n");
}
seg->fmt_ctx->flags |= AVFMT_FLAG_GENPTS;
seg->fmt_ctx->oformat->flags &= AVFMT_NOFILE;
printf("Initializing segment\n");
for (i = 0; i < fmt->nb_streams; i++) {
in_stream = fmt->streams[i];
//enum AVMediaType type = in_stream->codecpar->codec_type;
//if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_SUBTITLE) {
codec_ctx = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(codec_ctx, in_stream->codecpar);
out_stream = avformat_new_stream(seg->fmt_ctx, codec_ctx->codec);
//avcodec_parameters_to_context(out_stream->codec, in_stream->codecpar);
avcodec_free_context(&codec_ctx);
if (!out_stream) {
fprintf(stdout, "Failed allocating output stream\n");
continue;
}
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
if (ret < 0) {
fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
continue;
}
av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
//printf("Allocated output stream.\n");
/*out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; */
// }
}
seg->fmt_ctx->pb = seg->io_ctx;
ret = avformat_write_header(seg->fmt_ctx, NULL);
avio_flush(seg->io_ctx);
if (ret < 0) {
segment_close(seg);
fprintf(stderr, "Error occured while writing header: %s\n", av_err2str(ret));
}
printf("Initialized segment.\n");
//av_dump_format(seg->fmt_ctx, 0, "(memory)", 1);
*seg_p = seg;
return;
}