summaryrefslogtreecommitdiffstats
path: root/libvo/vo_lavc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvo/vo_lavc.c')
-rw-r--r--libvo/vo_lavc.c553
1 files changed, 0 insertions, 553 deletions
diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c
deleted file mode 100644
index b86cd76509..0000000000
--- a/libvo/vo_lavc.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * video encoding using libavformat
- * Copyright (C) 2010 Nicolas George <george@nsup.org>
- * Copyright (C) 2011 Rudolf Polzer <divVerent@xonotic.org>
- *
- * This file is part of MPlayer.
- *
- * MPlayer is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * MPlayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "mpcommon.h"
-#include "options.h"
-#include "fmt-conversion.h"
-#include "libmpcodecs/mp_image.h"
-#include "libmpcodecs/vfcap.h"
-#include "subopt-helper.h"
-#include "talloc.h"
-#include "video_out.h"
-
-#include "encode_lavc.h"
-
-#include "sub/sub.h"
-#include "sub/dec_sub.h"
-
-struct priv {
- uint8_t *buffer;
- size_t buffer_size;
- AVStream *stream;
- int have_first_packet;
-
- int harddup;
-
- double lastpts;
- int64_t lastipts;
- int64_t lastframeipts;
- double expected_next_pts;
- mp_image_t *lastimg;
- int lastimg_wants_osd;
- int lastdisplaycount;
-
- AVRational worst_time_base;
- int worst_time_base_is_stream;
-
- struct mp_csp_details colorspace;
-};
-
-static int preinit(struct vo *vo, const char *arg)
-{
- struct priv *vc;
- if (!encode_lavc_available(vo->encode_lavc_ctx)) {
- mp_msg(MSGT_ENCODE, MSGL_ERR,
- "vo-lavc: the option -o (output file) must be specified\n");
- return -1;
- }
- vo->priv = talloc_zero(vo, struct priv);
- vc = vo->priv;
- vc->harddup = vo->encode_lavc_ctx->options->harddup;
- vc->colorspace = (struct mp_csp_details) MP_CSP_DETAILS_DEFAULTS;
- return 0;
-}
-
-static void draw_image(struct vo *vo, mp_image_t *mpi, double pts);
-static void uninit(struct vo *vo)
-{
- struct priv *vc = vo->priv;
- if (!vc)
- return;
-
- if (vc->lastipts >= 0 && vc->stream)
- draw_image(vo, NULL, MP_NOPTS_VALUE);
-
- if (vc->lastimg) {
- // palette hack
- if (vc->lastimg->imgfmt == IMGFMT_RGB8
- || vc->lastimg->imgfmt == IMGFMT_BGR8)
- vc->lastimg->planes[1] = NULL;
- free_mp_image(vc->lastimg);
- vc->lastimg = NULL;
- }
-
- vo->priv = NULL;
-}
-
-static int config(struct vo *vo, uint32_t width, uint32_t height,
- uint32_t d_width, uint32_t d_height, uint32_t flags,
- uint32_t format)
-{
- struct priv *vc = vo->priv;
- enum PixelFormat pix_fmt = imgfmt2pixfmt(format);
- AVRational display_aspect_ratio, image_aspect_ratio;
- AVRational aspect;
-
- if (!vc)
- return -1;
-
- display_aspect_ratio.num = d_width;
- display_aspect_ratio.den = d_height;
- image_aspect_ratio.num = width;
- image_aspect_ratio.den = height;
- aspect = av_div_q(display_aspect_ratio, image_aspect_ratio);
-
- if (vc->stream) {
- /* NOTE:
- * in debug builds we get a "comparison between signed and unsigned"
- * warning here. We choose to ignore that; just because ffmpeg currently
- * uses a plain 'int' for these struct fields, it doesn't mean it always
- * will */
- if (width == vc->stream->codec->width &&
- height == vc->stream->codec->height) {
- if (aspect.num != vc->stream->codec->sample_aspect_ratio.num ||
- aspect.den != vc->stream->codec->sample_aspect_ratio.den) {
- /* aspect-only changes are not critical */
- mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: unsupported pixel aspect "
- "ratio change from %d:%d to %d:%d\n",
- vc->stream->codec->sample_aspect_ratio.num,
- vc->stream->codec->sample_aspect_ratio.den,
- aspect.num, aspect.den);
- }
- return 0;
- }
-
- /* FIXME Is it possible with raw video? */
- mp_msg(MSGT_ENCODE, MSGL_ERR,
- "vo-lavc: resolution changes not supported.\n");
- goto error;
- }
-
- vc->lastipts = MP_NOPTS_VALUE;
- vc->lastframeipts = MP_NOPTS_VALUE;
-
- if (pix_fmt == PIX_FMT_NONE)
- goto error; /* imgfmt2pixfmt already prints something */
-
- vc->stream = encode_lavc_alloc_stream(vo->encode_lavc_ctx,
- AVMEDIA_TYPE_VIDEO);
- vc->stream->sample_aspect_ratio = vc->stream->codec->sample_aspect_ratio =
- aspect;
- vc->stream->codec->width = width;
- vc->stream->codec->height = height;
- vc->stream->codec->pix_fmt = pix_fmt;
-
- encode_lavc_set_csp(vo->encode_lavc_ctx, vc->stream, vc->colorspace.format);
- encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->stream, vc->colorspace.levels_out);
-
- if (encode_lavc_open_codec(vo->encode_lavc_ctx, vc->stream) < 0)
- goto error;
-
- vc->colorspace.format = encode_lavc_get_csp(vo->encode_lavc_ctx, vc->stream);
- vc->colorspace.levels_out = encode_lavc_get_csp_levels(vo->encode_lavc_ctx, vc->stream);
-
- vc->buffer_size = 6 * width * height + 200;
- if (vc->buffer_size < FF_MIN_BUFFER_SIZE)
- vc->buffer_size = FF_MIN_BUFFER_SIZE;
- if (vc->buffer_size < sizeof(AVPicture))
- vc->buffer_size = sizeof(AVPicture);
-
- vc->buffer = talloc_size(vc, vc->buffer_size);
-
- vc->lastimg = alloc_mpi(width, height, format);
-
- // palette hack
- if (vc->lastimg->imgfmt == IMGFMT_RGB8 ||
- vc->lastimg->imgfmt == IMGFMT_BGR8)
- vc->lastimg->planes[1] = talloc_zero_size(vc, 1024);
-
- return 0;
-
-error:
- uninit(vo);
- return -1;
-}
-
-static int query_format(struct vo *vo, uint32_t format)
-{
- enum PixelFormat pix_fmt = imgfmt2pixfmt(format);
-
- if (!vo->encode_lavc_ctx)
- return 0;
-
- if (!encode_lavc_supports_pixfmt(vo->encode_lavc_ctx, pix_fmt))
- return 0;
-
- return
- VFCAP_CSP_SUPPORTED |
- // we can do it
- VFCAP_CSP_SUPPORTED_BY_HW |
- // we don't convert colorspaces here
- VFCAP_OSD |
- // we have OSD
- VOCAP_NOSLICES;
- // we don't use slices
-}
-
-static void write_packet(struct vo *vo, int size, AVPacket *packet)
-{
- struct priv *vc = vo->priv;
-
- if (size < 0) {
- mp_msg(MSGT_ENCODE, MSGL_ERR, "vo-lavc: error encoding\n");
- return;
- }
-
- if (size > 0) {
- packet->stream_index = vc->stream->index;
- if (packet->pts != AV_NOPTS_VALUE) {
- packet->pts = av_rescale_q(packet->pts,
- vc->stream->codec->time_base,
- vc->stream->time_base);
- } else {
- mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: codec did not provide pts\n");
- packet->pts = av_rescale_q(vc->lastipts, vc->worst_time_base,
- vc->stream->time_base);
- }
- if (packet->dts != AV_NOPTS_VALUE) {
- packet->dts = av_rescale_q(packet->dts,
- vc->stream->codec->time_base,
- vc->stream->time_base);
- }
- if (packet->duration > 0) {
- packet->duration = av_rescale_q(packet->duration,
- vc->stream->codec->time_base,
- vc->stream->time_base);
- } else {
- // HACK: libavformat calculates dts wrong if the initial packet
- // duration is not set, but ONLY if the time base is "high" and if we
- // have b-frames!
- if (!packet->duration)
- if (!vc->have_first_packet)
- if (vc->stream->codec->has_b_frames
- || vc->stream->codec->max_b_frames)
- if (vc->stream->time_base.num * 1000LL <=
- vc->stream->time_base.den)
- packet->duration = FFMAX(1, av_rescale_q(1,
- vc->stream->codec->time_base, vc->stream->time_base));
- }
-
- if (encode_lavc_write_frame(vo->encode_lavc_ctx, packet) < 0) {
- mp_msg(MSGT_ENCODE, MSGL_ERR, "vo-lavc: error writing\n");
- return;
- }
-
- vc->have_first_packet = 1;
- }
-}
-
-static int encode_video(struct vo *vo, AVFrame *frame, AVPacket *packet)
-{
- struct priv *vc = vo->priv;
- if (encode_lavc_oformat_flags(vo->encode_lavc_ctx) & AVFMT_RAWPICTURE) {
- if (!frame)
- return 0;
- memcpy(vc->buffer, frame, sizeof(AVPicture));
- mp_msg(MSGT_ENCODE, MSGL_DBG2, "vo-lavc: got pts %f\n",
- frame->pts * (double) vc->stream->codec->time_base.num /
- (double) vc->stream->codec->time_base.den);
- packet->size = sizeof(AVPicture);
- return packet->size;
- } else {
- int got_packet = 0;
- int status = avcodec_encode_video2(vc->stream->codec, packet,
- frame, &got_packet);
- int size = (status < 0) ? status : got_packet ? packet->size : 0;
-
- if (frame)
- mp_msg(MSGT_ENCODE, MSGL_DBG2, "vo-lavc: got pts %f; out size: %d\n",
- frame->pts * (double) vc->stream->codec->time_base.num /
- (double) vc->stream->codec->time_base.den, size);
-
- encode_lavc_write_stats(vo->encode_lavc_ctx, vc->stream);
- return size;
- }
-}
-
-static void draw_image(struct vo *vo, mp_image_t *mpi, double pts)
-{
- struct priv *vc = vo->priv;
- struct encode_lavc_context *ectx = vo->encode_lavc_ctx;
- int i, size;
- AVFrame *frame;
- AVCodecContext *avc;
- int64_t frameipts;
- double nextpts;
-
- if (!vc)
- return;
- if (!encode_lavc_start(ectx)) {
- mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: NOTE: skipped initial video frame (probably because audio is not there yet)\n");
- return;
- }
- if (pts == MP_NOPTS_VALUE) {
- if (mpi)
- mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: frame without pts, please report; synthesizing pts instead\n");
- pts = vc->expected_next_pts;
- }
-
- avc = vc->stream->codec;
-
- if (vc->worst_time_base.den == 0) {
- //if (avc->time_base.num / avc->time_base.den >= vc->stream->time_base.num / vc->stream->time_base.den)
- if (avc->time_base.num * (double) vc->stream->time_base.den >=
- vc->stream->time_base.num * (double) avc->time_base.den) {
- mp_msg(MSGT_ENCODE, MSGL_V, "vo-lavc: NOTE: using codec time base "
- "(%d/%d) for frame dropping; the stream base (%d/%d) is "
- "not worse.\n", (int)avc->time_base.num,
- (int)avc->time_base.den, (int)vc->stream->time_base.num,
- (int)vc->stream->time_base.den);
- vc->worst_time_base = avc->time_base;
- vc->worst_time_base_is_stream = 0;
- } else {
- mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: NOTE: not using codec time "
- "base (%d/%d) for frame dropping; the stream base (%d/%d) "
- "is worse.\n", (int)avc->time_base.num,
- (int)avc->time_base.den, (int)vc->stream->time_base.num,
- (int)vc->stream->time_base.den);
- vc->worst_time_base = vc->stream->time_base;
- vc->worst_time_base_is_stream = 1;
- }
-
- // NOTE: we use the following "axiom" of av_rescale_q:
- // if time base A is worse than time base B, then
- // av_rescale_q(av_rescale_q(x, A, B), B, A) == x
- // this can be proven as long as av_rescale_q rounds to nearest, which
- // it currently does
-
- // av_rescale_q(x, A, B) * B = "round x*A to nearest multiple of B"
- // and:
- // av_rescale_q(av_rescale_q(x, A, B), B, A) * A
- // == "round av_rescale_q(x, A, B)*B to nearest multiple of A"
- // == "round 'round x*A to nearest multiple of B' to nearest multiple of A"
- //
- // assume this fails. Then there is a value of x*A, for which the
- // nearest multiple of B is outside the range [(x-0.5)*A, (x+0.5)*A[.
- // Absurd, as this range MUST contain at least one multiple of B.
- }
-
- double timeunit = (double)vc->worst_time_base.num / vc->worst_time_base.den;
-
- double outpts;
- if (ectx->options->rawts)
- outpts = pts;
- else if (ectx->options->copyts) {
- // fix the discontinuity pts offset
- nextpts = pts;
- if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
- ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
- }
- else if (fabs(nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts) > 30) {
- mp_msg(MSGT_ENCODE, MSGL_WARN,
- "vo-lavc: detected an unexpected discontinuity (pts jumped by "
- "%f seconds)\n",
- nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts);
- ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
- }
-
- outpts = pts + ectx->discontinuity_pts_offset;
- }
- else {
- // adjust pts by knowledge of audio pts vs audio playback time
- double duration = 0;
- if (ectx->last_video_in_pts != MP_NOPTS_VALUE)
- duration = pts - ectx->last_video_in_pts;
- if (duration < 0)
- duration = timeunit; // XXX warn about discontinuity?
- outpts = vc->lastpts + duration;
- if (ectx->audio_pts_offset != MP_NOPTS_VALUE) {
- double adj = outpts - pts - ectx->audio_pts_offset;
- adj = FFMIN(adj, duration * 0.1);
- adj = FFMAX(adj, -duration * 0.1);
- outpts -= adj;
- }
- }
- vc->lastpts = outpts;
- ectx->last_video_in_pts = pts;
- frameipts = floor((outpts + encode_lavc_getoffset(ectx, vc->stream))
- / timeunit + 0.5);
-
- // calculate expected pts of next video frame
- vc->expected_next_pts = pts + timeunit;
-
- if (!ectx->options->rawts && ectx->options->copyts) {
- // set next allowed output pts value
- nextpts = vc->expected_next_pts + ectx->discontinuity_pts_offset;
- if (nextpts > ectx->next_in_pts)
- ectx->next_in_pts = nextpts;
- }
-
- // never-drop mode
- if (ectx->options->neverdrop && frameipts <= vc->lastipts) {
- mp_msg(MSGT_ENCODE, MSGL_INFO, "vo-lavc: -oneverdrop increased pts by %d\n",
- (int) (vc->lastipts - frameipts + 1));
- frameipts = vc->lastipts + 1;
- vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->stream);
- }
-
- if (vc->lastipts != MP_NOPTS_VALUE) {
- frame = avcodec_alloc_frame();
-
- // we have a valid image in lastimg
- while (vc->lastipts < frameipts) {
- int64_t thisduration = vc->harddup ? 1 : (frameipts - vc->lastipts);
- AVPacket packet;
-
- avcodec_get_frame_defaults(frame);
-
- // this is a nop, unless the worst time base is the STREAM time base
- frame->pts = av_rescale_q(vc->lastipts, vc->worst_time_base,
- avc->time_base);
-
- for (i = 0; i < 4; i++) {
- frame->data[i] = vc->lastimg->planes[i];
- frame->linesize[i] = vc->lastimg->stride[i];
- }
- frame->quality = avc->global_quality;
-
- av_init_packet(&packet);
- packet.data = vc->buffer;
- packet.size = vc->buffer_size;
- size = encode_video(vo, frame, &packet);
- write_packet(vo, size, &packet);
-
- vc->lastipts += thisduration;
- ++vc->lastdisplaycount;
- }
-
- avcodec_free_frame(&frame);
- }
-
- if (!mpi) {
- // finish encoding
- do {
- AVPacket packet;
- av_init_packet(&packet);
- packet.data = vc->buffer;
- packet.size = vc->buffer_size;
- size = encode_video(vo, NULL, &packet);
- write_packet(vo, size, &packet);
- } while (size > 0);
- } else {
- if (frameipts >= vc->lastframeipts) {
- if (vc->lastframeipts != MP_NOPTS_VALUE && vc->lastdisplaycount != 1)
- mp_msg(MSGT_ENCODE, MSGL_INFO,
- "vo-lavc: Frame at pts %d got displayed %d times\n",
- (int) vc->lastframeipts, vc->lastdisplaycount);
- copy_mpi(vc->lastimg, mpi);
- vc->lastimg_wants_osd = true;
-
- // palette hack
- if (vc->lastimg->imgfmt == IMGFMT_RGB8 ||
- vc->lastimg->imgfmt == IMGFMT_BGR8)
- memcpy(vc->lastimg->planes[1], mpi->planes[1], 1024);
-
- vc->lastframeipts = vc->lastipts = frameipts;
- if (ectx->options->rawts && vc->lastipts < 0) {
- mp_msg(MSGT_ENCODE, MSGL_ERR, "vo-lavc: why does this happen? DEBUG THIS! vc->lastipts = %lld\n", (long long) vc->lastipts);
- vc->lastipts = -1;
- }
- vc->lastdisplaycount = 0;
- } else {
- mp_msg(MSGT_ENCODE, MSGL_INFO, "vo-lavc: Frame at pts %d got dropped "
- "entirely because pts went backwards\n", (int) frameipts);
- vc->lastimg_wants_osd = false;
- }
- }
-}
-
-static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration)
-{
-}
-
-static void check_events(struct vo *vo)
-{
-}
-
-static void draw_osd(struct vo *vo, struct osd_state *osd)
-{
- struct priv *vc = vo->priv;
-
- if (vc->lastimg && vc->lastimg_wants_osd) {
- struct aspect_data asp = vo->aspdat;
- double sar = (double)asp.orgw / asp.orgh;
- double dar = (double)asp.prew / asp.preh;
-
- struct mp_osd_res dim = {
- .w = asp.orgw,
- .h = asp.orgh,
- .display_par = sar / dar,
- .video_par = dar / sar,
- };
-
- mp_image_set_colorspace_details(vc->lastimg, &vc->colorspace);
-
- osd_draw_on_image(osd, dim, osd->vo_pts, OSD_DRAW_SUB_ONLY, vc->lastimg);
- }
-}
-
-static int control(struct vo *vo, uint32_t request, void *data)
-{
- struct priv *vc = vo->priv;
- switch (request) {
- case VOCTRL_QUERY_FORMAT:
- return query_format(vo, *((uint32_t *)data));
- case VOCTRL_DRAW_IMAGE:
- draw_image(vo, (mp_image_t *)data, vo->next_pts);
- return 0;
- case VOCTRL_SET_YUV_COLORSPACE:
- vc->colorspace = *(struct mp_csp_details *)data;
- if (vc->stream) {
- encode_lavc_set_csp(vo->encode_lavc_ctx, vc->stream, vc->colorspace.format);
- encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->stream, vc->colorspace.levels_out);
- vc->colorspace.format = encode_lavc_get_csp(vo->encode_lavc_ctx, vc->stream);
- vc->colorspace.levels_out = encode_lavc_get_csp_levels(vo->encode_lavc_ctx, vc->stream);
- }
- return 1;
- case VOCTRL_GET_YUV_COLORSPACE:
- *(struct mp_csp_details *)data = vc->colorspace;
- return 1;
- }
- return VO_NOTIMPL;
-}
-
-const struct vo_driver video_out_lavc = {
- .is_new = true,
- .buffer_frames = false,
- .info = &(const struct vo_info_s){
- "video encoding using libavcodec",
- "lavc",
- "Nicolas George <george@nsup.org>, Rudolf Polzer <divVerent@xonotic.org>",
- ""
- },
- .preinit = preinit,
- .config = config,
- .control = control,
- .uninit = uninit,
- .check_events = check_events,
- .draw_osd = draw_osd,
- .flip_page_timed = flip_page_timed,
-};
-
-// vim: sw=4 ts=4 et tw=80