|
|
|
|
@ -357,48 +357,29 @@ static int64_t output_avio_mem_seek(void *opaque, int64_t offset, int whence) {
|
|
|
|
|
return o->mempos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool output_config(sink_t *sink, output_t *output, const format_t *requested_format,
|
|
|
|
|
format_t *actual_format)
|
|
|
|
|
{
|
|
|
|
|
const char *err;
|
|
|
|
|
int av_ret = 0;
|
|
|
|
|
|
|
|
|
|
format_t req_fmt = *requested_format;
|
|
|
|
|
|
|
|
|
|
// if we've already done this and don't care about the sample format,
|
|
|
|
|
// restore the already determined sample format
|
|
|
|
|
if (req_fmt.format == -1 && output->requested_format.format != -1)
|
|
|
|
|
req_fmt.format = output->requested_format.format;
|
|
|
|
|
|
|
|
|
|
// anything to do?
|
|
|
|
|
if (G_LIKELY(format_eq(&req_fmt, &output->requested_format)))
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
static const char *output_setup(output_t *output, const format_t *requested_format, format_t *req_fmt) {
|
|
|
|
|
output_shutdown(output, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
err = "failed to alloc format context";
|
|
|
|
|
output->fmtctx = avformat_alloc_context();
|
|
|
|
|
if (!output->fmtctx)
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to alloc format context";
|
|
|
|
|
output->fmtctx->oformat = av_guess_format(output->file_format, NULL, NULL);
|
|
|
|
|
err = "failed to determine output format";
|
|
|
|
|
if (!output->fmtctx->oformat)
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to determine output format";
|
|
|
|
|
|
|
|
|
|
// mask the channel multiplier from external view
|
|
|
|
|
output->requested_format = *requested_format;
|
|
|
|
|
|
|
|
|
|
if (encoder_config(output->encoder, output_codec, mp3_bitrate, 0, &req_fmt, &output->actual_format))
|
|
|
|
|
goto err;
|
|
|
|
|
if (encoder_config(output->encoder, output_codec, mp3_bitrate, 0, req_fmt, &output->actual_format))
|
|
|
|
|
return "failed to configure encoder";
|
|
|
|
|
|
|
|
|
|
// save the sample format
|
|
|
|
|
if (requested_format->format == -1)
|
|
|
|
|
output->requested_format.format = output->actual_format.format;
|
|
|
|
|
|
|
|
|
|
err = "failed to alloc output stream";
|
|
|
|
|
output->avst = avformat_new_stream(output->fmtctx, output->encoder->avc.codec);
|
|
|
|
|
if (!output->avst)
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to alloc output stream";
|
|
|
|
|
output->avst->time_base = output->encoder->avc.avcctx->time_base;
|
|
|
|
|
|
|
|
|
|
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 0, 0)
|
|
|
|
|
@ -434,38 +415,32 @@ static bool output_config(sink_t *sink, output_t *output, const format_t *reques
|
|
|
|
|
g_free(full_fn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = "failed to find unused output file number";
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to find unused output file number";
|
|
|
|
|
|
|
|
|
|
got_fn:
|
|
|
|
|
output->filename = full_fn;
|
|
|
|
|
|
|
|
|
|
err = "failed to open output file";
|
|
|
|
|
output->fp = fopen(full_fn, (output_storage & OUTPUT_STORAGE_DB) ? "wb+" : "wb");
|
|
|
|
|
if (!output->fp)
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to open output file";
|
|
|
|
|
|
|
|
|
|
if (output_buffer > 0) {
|
|
|
|
|
err = "failed to alloc I/O buffer";
|
|
|
|
|
output->iobuf = g_malloc(output_buffer);
|
|
|
|
|
if (!output->iobuf)
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to alloc I/O buffer";
|
|
|
|
|
|
|
|
|
|
err = "failed to set I/O buffer";
|
|
|
|
|
if (setvbuf(output->fp, output->iobuf, _IOFBF, output_buffer))
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to set I/O buffer";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
err = "failed to set unuffered I/O";
|
|
|
|
|
if (setvbuf(output->fp, NULL, _IONBF, 0))
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to set unuffered I/O";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
no_output_file:
|
|
|
|
|
err = "failed to alloc avio buffer";
|
|
|
|
|
void *avio_buf = av_malloc(DEFAULT_AVIO_BUFSIZE);
|
|
|
|
|
if (!avio_buf)
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to alloc avio buffer";
|
|
|
|
|
|
|
|
|
|
if (!(output_storage & OUTPUT_STORAGE_MEMORY))
|
|
|
|
|
output->avioctx = avio_alloc_context(avio_buf, DEFAULT_AVIO_BUFSIZE, 1, output,
|
|
|
|
|
@ -475,18 +450,18 @@ no_output_file:
|
|
|
|
|
output->avioctx = avio_alloc_context(avio_buf, DEFAULT_AVIO_BUFSIZE, 1, output,
|
|
|
|
|
NULL, output_avio_mem_write, output_avio_mem_seek);
|
|
|
|
|
}
|
|
|
|
|
err = "failed to alloc AVIOContext";
|
|
|
|
|
if (!output->avioctx) {
|
|
|
|
|
av_freep(&avio_buf);
|
|
|
|
|
goto err;
|
|
|
|
|
return "failed to alloc AVIOContext";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
output->fmtctx->pb = output->avioctx;
|
|
|
|
|
|
|
|
|
|
err = "failed to write header";
|
|
|
|
|
av_ret = avformat_write_header(output->fmtctx, NULL);
|
|
|
|
|
if (av_ret)
|
|
|
|
|
goto err;
|
|
|
|
|
int av_ret = avformat_write_header(output->fmtctx, NULL);
|
|
|
|
|
if (av_ret) {
|
|
|
|
|
ilog(LOG_ERR, "Error returned from libav: %s", av_error(av_ret));
|
|
|
|
|
return "failed to write header";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (output_chmod && output->filename)
|
|
|
|
|
if (chmod(output->filename, output_chmod))
|
|
|
|
|
@ -504,17 +479,34 @@ no_output_file:
|
|
|
|
|
|
|
|
|
|
db_config_stream(output);
|
|
|
|
|
ilog(LOG_INFO, "Opened output media file '%s' for writing", full_fn ?: "(mem stream)");
|
|
|
|
|
done:
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool output_config(sink_t *sink, output_t *output, const format_t *requested_format,
|
|
|
|
|
format_t *actual_format)
|
|
|
|
|
{
|
|
|
|
|
format_t req_fmt = *requested_format;
|
|
|
|
|
|
|
|
|
|
// if we've already done this and don't care about the sample format,
|
|
|
|
|
// restore the already determined sample format
|
|
|
|
|
if (req_fmt.format == -1 && output->requested_format.format != -1)
|
|
|
|
|
req_fmt.format = output->requested_format.format;
|
|
|
|
|
|
|
|
|
|
// anything to do?
|
|
|
|
|
if (G_UNLIKELY(!format_eq(&req_fmt, &output->requested_format))) {
|
|
|
|
|
const char *err = output_setup(output, requested_format, &req_fmt);
|
|
|
|
|
if (err) {
|
|
|
|
|
output_shutdown(output, NULL, NULL);
|
|
|
|
|
ilog(LOG_ERR, "Error configuring media output: %s", err);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (actual_format)
|
|
|
|
|
*actual_format = output->actual_format;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
output_shutdown(output, NULL, NULL);
|
|
|
|
|
ilog(LOG_ERR, "Error configuring media output: %s", err);
|
|
|
|
|
if (av_ret)
|
|
|
|
|
ilog(LOG_ERR, "Error returned from libav: %s", av_error(av_ret));
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|