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.
1264 lines
43 KiB
1264 lines
43 KiB
diff --git a/operations/external/ff-load.c b/operations/external/ff-load.c |
|
index 0d9a4f3fbef422a8ff548820ee8843e0a2ffa7ec..ec3b747f976a31cfabe811ba03fb7487839342f0 100644 |
|
--- a/operations/external/ff-load.c |
|
+++ b/operations/external/ff-load.c |
|
@@ -62,9 +62,11 @@ property_audio_fragment (audio, _("audio"), 0) |
|
#include <limits.h> |
|
#include <stdlib.h> |
|
|
|
+#include <libavutil/channel_layout.h> |
|
#include <libavutil/avutil.h> |
|
#include <libavutil/imgutils.h> |
|
#include <libavformat/avformat.h> |
|
+#include <libavcodec/avcodec.h> |
|
#include <libswscale/swscale.h> |
|
|
|
|
|
@@ -74,11 +76,12 @@ typedef struct |
|
gint height; |
|
gdouble fps; |
|
gint codec_delay; |
|
+ int64_t first_dts; |
|
|
|
gchar *loadedfilename; /* to remember which file is "cached" */ |
|
|
|
AVFormatContext *audio_fcontext; |
|
- AVCodec *audio_codec; |
|
+ const AVCodec *audio_codec; |
|
int audio_index; |
|
GList *audio_track; |
|
long audio_cursor_pos; |
|
@@ -90,8 +93,10 @@ typedef struct |
|
AVFormatContext *video_fcontext; |
|
int video_index; |
|
AVStream *video_stream; |
|
+ AVCodecContext *video_ctx; |
|
AVStream *audio_stream; |
|
- AVCodec *video_codec; |
|
+ AVCodecContext *audio_ctx; |
|
+ const AVCodec *video_codec; |
|
AVFrame *lavc_frame; |
|
AVFrame *rgb_frame; |
|
glong prevframe; /* previously decoded frame number */ |
|
@@ -140,10 +145,8 @@ ff_cleanup (GeglProperties *o) |
|
{ |
|
clear_audio_track (o); |
|
g_free (p->loadedfilename); |
|
- if (p->video_stream && p->video_stream->codec) |
|
- avcodec_close (p->video_stream->codec); |
|
- if (p->audio_stream && p->audio_stream->codec) |
|
- avcodec_close (p->audio_stream->codec); |
|
+ avcodec_free_context (&p->video_ctx); |
|
+ avcodec_free_context (&p->audio_ctx); |
|
if (p->video_fcontext) |
|
avformat_close_input(&p->video_fcontext); |
|
if (p->audio_fcontext) |
|
@@ -202,14 +205,14 @@ decode_audio (GeglOperation *operation, |
|
if (av_seek_frame (p->audio_fcontext, p->audio_stream->index, seek_target, (AVSEEK_FLAG_BACKWARD)) < 0) |
|
fprintf (stderr, "audio seek error!\n"); |
|
else |
|
- avcodec_flush_buffers (p->audio_stream->codec); |
|
+ avcodec_flush_buffers (p->audio_ctx); |
|
|
|
} |
|
|
|
while (p->prevapts <= pts2) |
|
{ |
|
AVPacket pkt = {0,}; |
|
- int decoded_bytes; |
|
+ int ret; |
|
|
|
if (av_read_frame (p->audio_fcontext, &pkt) < 0) |
|
{ |
|
@@ -219,77 +222,93 @@ decode_audio (GeglOperation *operation, |
|
if (pkt.stream_index==p->audio_index && p->audio_stream) |
|
{ |
|
static AVFrame frame; |
|
- int got_frame; |
|
|
|
- decoded_bytes = avcodec_decode_audio4(p->audio_stream->codec, |
|
- &frame, &got_frame, &pkt); |
|
- |
|
- if (decoded_bytes < 0) |
|
+ ret = avcodec_send_packet (p->audio_ctx, &pkt); |
|
+ if (ret < 0) |
|
{ |
|
- fprintf (stderr, "avcodec_decode_audio4 failed for %s\n", |
|
+ fprintf (stderr, "avcodec_send_packet failed for %s\n", |
|
o->path); |
|
} |
|
- |
|
- if (got_frame) { |
|
- int samples_left = frame.nb_samples; |
|
- int si = 0; |
|
- |
|
- while (samples_left) |
|
+ while (ret == 0) |
|
{ |
|
- int sample_count = samples_left; |
|
- int channels = MIN(p->audio_stream->codecpar->channels, GEGL_MAX_AUDIO_CHANNELS); |
|
- GeglAudioFragment *af = gegl_audio_fragment_new (o->audio_sample_rate, channels, |
|
- AV_CH_LAYOUT_STEREO, samples_left); |
|
-//); |
|
- switch (p->audio_stream->codec->sample_fmt) |
|
- { |
|
- case AV_SAMPLE_FMT_FLT: |
|
- for (gint i = 0; i < sample_count; i++) |
|
- for (gint c = 0; c < channels; c++) |
|
- af->data[c][i] = ((int16_t *)frame.data[0])[(i + si) * channels + c]; |
|
- break; |
|
- case AV_SAMPLE_FMT_FLTP: |
|
- for (gint i = 0; i < sample_count; i++) |
|
- for (gint c = 0; c < channels; c++) |
|
- { |
|
- af->data[c][i] = ((float *)frame.data[c])[i + si]; |
|
- } |
|
- break; |
|
- case AV_SAMPLE_FMT_S16: |
|
- for (gint i = 0; i < sample_count; i++) |
|
- for (gint c = 0; c < channels; c++) |
|
- af->data[c][i] = ((int16_t *)frame.data[0])[(i + si) * channels + c] / 32768.0; |
|
- break; |
|
- case AV_SAMPLE_FMT_S16P: |
|
- for (gint i = 0; i < sample_count; i++) |
|
- for (gint c = 0; c < channels; c++) |
|
- af->data[c][i] = ((int16_t *)frame.data[c])[i + si] / 32768.0; |
|
- break; |
|
- case AV_SAMPLE_FMT_S32: |
|
- for (gint i = 0; i < sample_count; i++) |
|
- for (gint c = 0; c < channels; c++) |
|
- af->data[c][i] = ((int32_t *)frame.data[0])[(i + si) * channels + c] / 2147483648.0; |
|
+ ret = avcodec_receive_frame (p->audio_ctx, &frame); |
|
+ if (ret == AVERROR(EAGAIN)) |
|
+ { |
|
+ // no more frames; should send the next packet now |
|
+ ret = 0; |
|
break; |
|
- case AV_SAMPLE_FMT_S32P: |
|
- for (gint i = 0; i < sample_count; i++) |
|
- for (gint c = 0; c < channels; c++) |
|
- af->data[c][i] = ((int32_t *)frame.data[c])[i + si] / 2147483648.0; |
|
+ } |
|
+ else if (ret < 0) |
|
+ { |
|
+ fprintf (stderr, "avcodec_receive_frame failed for %s\n", |
|
+ o->path); |
|
break; |
|
- default: |
|
- g_warning ("undealt with sample format\n"); |
|
} |
|
- gegl_audio_fragment_set_sample_count (af, sample_count); |
|
- gegl_audio_fragment_set_pos (af, |
|
- (long int)av_rescale_q ((pkt.pts), p->audio_stream->time_base, AV_TIME_BASE_Q) * o->audio_sample_rate /AV_TIME_BASE); |
|
- |
|
- p->audio_pos += sample_count; |
|
- p->audio_track = g_list_append (p->audio_track, af); |
|
- |
|
- samples_left -= sample_count; |
|
- si += sample_count; |
|
- } |
|
- p->prevapts = pkt.pts * av_q2d (p->audio_stream->time_base); |
|
- } |
|
+ int samples_left = frame.nb_samples; |
|
+ int si = 0; |
|
+ |
|
+ while (samples_left) |
|
+ { |
|
+ int sample_count = samples_left; |
|
+ int channels = MIN(p->audio_stream->codecpar->channels, GEGL_MAX_AUDIO_CHANNELS); |
|
+ GeglAudioFragment *af = gegl_audio_fragment_new (o->audio_sample_rate, channels, |
|
+ AV_CH_LAYOUT_STEREO, samples_left); |
|
+ //); |
|
+ switch (p->audio_ctx->sample_fmt) |
|
+ { |
|
+ case AV_SAMPLE_FMT_FLT: |
|
+ for (gint i = 0; i < sample_count; i++) |
|
+ for (gint c = 0; c < channels; c++) |
|
+ af->data[c][i] = ((int16_t *)frame.data[0])[(i + si) * channels + c]; |
|
+ break; |
|
+ case AV_SAMPLE_FMT_FLTP: |
|
+ for (gint i = 0; i < sample_count; i++) |
|
+ for (gint c = 0; c < channels; c++) |
|
+ { |
|
+ af->data[c][i] = ((float *)frame.data[c])[i + si]; |
|
+ } |
|
+ break; |
|
+ case AV_SAMPLE_FMT_S16: |
|
+ for (gint i = 0; i < sample_count; i++) |
|
+ for (gint c = 0; c < channels; c++) |
|
+ af->data[c][i] = ((int16_t *)frame.data[0])[(i + si) * channels + c] / 32768.0; |
|
+ break; |
|
+ case AV_SAMPLE_FMT_S16P: |
|
+ for (gint i = 0; i < sample_count; i++) |
|
+ for (gint c = 0; c < channels; c++) |
|
+ af->data[c][i] = ((int16_t *)frame.data[c])[i + si] / 32768.0; |
|
+ break; |
|
+ case AV_SAMPLE_FMT_S32: |
|
+ for (gint i = 0; i < sample_count; i++) |
|
+ for (gint c = 0; c < channels; c++) |
|
+ af->data[c][i] = ((int32_t *)frame.data[0])[(i + si) * channels + c] / 2147483648.0; |
|
+ break; |
|
+ case AV_SAMPLE_FMT_S32P: |
|
+ for (gint i = 0; i < sample_count; i++) |
|
+ for (gint c = 0; c < channels; c++) |
|
+ af->data[c][i] = ((int32_t *)frame.data[c])[i + si] / 2147483648.0; |
|
+ break; |
|
+ default: |
|
+ g_warning ("undealt with sample format\n"); |
|
+ } |
|
+ gegl_audio_fragment_set_sample_count (af, sample_count); |
|
+ gegl_audio_fragment_set_pos ( |
|
+ af, |
|
+ (long int)av_rescale_q ( |
|
+ (pkt.pts), |
|
+ p->audio_stream->time_base, |
|
+ AV_TIME_BASE_Q |
|
+ ) * o->audio_sample_rate / AV_TIME_BASE |
|
+ ); |
|
+ |
|
+ p->audio_pos += sample_count; |
|
+ p->audio_track = g_list_append (p->audio_track, af); |
|
+ |
|
+ samples_left -= sample_count; |
|
+ si += sample_count; |
|
+ } |
|
+ p->prevapts = pkt.pts * av_q2d (p->audio_stream->time_base); |
|
+ } |
|
} |
|
av_packet_unref (&pkt); |
|
} |
|
@@ -325,12 +344,12 @@ decode_frame (GeglOperation *operation, |
|
if (frame < 2 || frame > prevframe + 64 || frame < prevframe ) |
|
{ |
|
int64_t seek_target = av_rescale_q (((frame) * AV_TIME_BASE * 1.0) / o->frame_rate |
|
-, AV_TIME_BASE_Q, p->video_stream->time_base) / p->video_stream->codec->ticks_per_frame; |
|
+, AV_TIME_BASE_Q, p->video_stream->time_base) / p->video_ctx->ticks_per_frame; |
|
|
|
if (av_seek_frame (p->video_fcontext, p->video_index, seek_target, (AVSEEK_FLAG_BACKWARD )) < 0) |
|
fprintf (stderr, "video seek error!\n"); |
|
else |
|
- avcodec_flush_buffers (p->video_stream->codec); |
|
+ avcodec_flush_buffers (p->video_ctx); |
|
|
|
prevframe = -1; |
|
} |
|
@@ -340,7 +359,7 @@ decode_frame (GeglOperation *operation, |
|
int got_picture = 0; |
|
do |
|
{ |
|
- int decoded_bytes; |
|
+ int ret; |
|
AVPacket pkt = {0,}; |
|
|
|
do |
|
@@ -354,33 +373,52 @@ decode_frame (GeglOperation *operation, |
|
} |
|
while (pkt.stream_index != p->video_index); |
|
|
|
- decoded_bytes = avcodec_decode_video2 ( |
|
- p->video_stream->codec, p->lavc_frame, |
|
- &got_picture, &pkt); |
|
- if (decoded_bytes < 0) |
|
+ ret = avcodec_send_packet (p->video_ctx, &pkt); |
|
+ if (ret < 0) |
|
{ |
|
- fprintf (stderr, "avcodec_decode_video failed for %s\n", |
|
+ fprintf (stderr, "avcodec_send_packet failed for %s\n", |
|
o->path); |
|
return -1; |
|
} |
|
- |
|
- if(got_picture) |
|
- { |
|
- if ((pkt.dts == pkt.pts) || (p->lavc_frame->key_frame!=0)) |
|
- { |
|
- p->lavc_frame->pts = (p->video_stream->cur_dts - |
|
- p->video_stream->first_dts); |
|
- p->prevpts = av_rescale_q (p->lavc_frame->pts, |
|
- p->video_stream->time_base, |
|
- AV_TIME_BASE_Q) * 1.0 / AV_TIME_BASE; |
|
- decodeframe = roundf( p->prevpts * o->frame_rate); |
|
- } |
|
- else |
|
- { |
|
- p->prevpts += 1.0 / o->frame_rate; |
|
- decodeframe = roundf ( p->prevpts * o->frame_rate); |
|
- } |
|
- } |
|
+ while (ret == 0) |
|
+ { |
|
+ if (!p->first_dts) |
|
+ p->first_dts = pkt.dts; |
|
+ ret = avcodec_receive_frame (p->video_ctx, p->lavc_frame); |
|
+ if (ret == AVERROR(EAGAIN)) |
|
+ { |
|
+ // no more frames; should send the next packet now |
|
+ ret = 0; |
|
+ break; |
|
+ } |
|
+ else if (ret < 0) |
|
+ { |
|
+ fprintf (stderr, "avcodec_receive_frame failed for %s\n", |
|
+ o->path); |
|
+ break; |
|
+ } |
|
+ got_picture = 1; |
|
+ if ((pkt.dts == pkt.pts) || (p->lavc_frame->key_frame!=0)) |
|
+ { |
|
+ // cur_dts and first_dts are moved to libavformat/internal.h |
|
+ /* |
|
+ p->lavc_frame->pts = (p->video_stream->cur_dts - |
|
+ p->video_stream->first_dts); |
|
+ */ |
|
+ p->lavc_frame->pts = pkt.dts - p->first_dts; |
|
+ p->prevpts = av_rescale_q (p->lavc_frame->pts, |
|
+ p->video_stream->time_base, |
|
+ AV_TIME_BASE_Q) * 1.0 / AV_TIME_BASE; |
|
+ decodeframe = roundf( p->prevpts * o->frame_rate); |
|
+ } |
|
+ else |
|
+ { |
|
+ p->prevpts += 1.0 / o->frame_rate; |
|
+ decodeframe = roundf ( p->prevpts * o->frame_rate); |
|
+ } |
|
+ if (decodeframe > frame + p->codec_delay) |
|
+ break; |
|
+ } |
|
#if 0 |
|
if (decoded_bytes != pkt.size) |
|
fprintf (stderr, "bytes left!\n"); |
|
@@ -429,6 +467,7 @@ prepare (GeglOperation *operation) |
|
if (err < 0) |
|
{ |
|
print_error (o->path, err); |
|
+ return; |
|
} |
|
err = avformat_find_stream_info (p->video_fcontext, NULL); |
|
if (err < 0) |
|
@@ -440,6 +479,7 @@ prepare (GeglOperation *operation) |
|
if (err < 0) |
|
{ |
|
print_error (o->path, err); |
|
+ return; |
|
} |
|
err = avformat_find_stream_info (p->audio_fcontext, NULL); |
|
if (err < 0) |
|
@@ -467,16 +507,26 @@ prepare (GeglOperation *operation) |
|
{ |
|
p->video_codec = avcodec_find_decoder (p->video_stream->codecpar->codec_id); |
|
if (p->video_codec == NULL) |
|
- g_warning ("video codec not found"); |
|
- p->video_stream->codec->err_recognition = AV_EF_IGNORE_ERR | |
|
+ { |
|
+ g_warning ("video codec not found"); |
|
+ p->video_ctx = NULL; |
|
+ return; |
|
+ } |
|
+ p->video_ctx = avcodec_alloc_context3 (p->video_codec); |
|
+ if (avcodec_parameters_to_context (p->video_ctx, p->video_stream->codecpar) < 0) |
|
+ { |
|
+ fprintf (stderr, "cannot copy video codec parameters\n"); |
|
+ return; |
|
+ } |
|
+ p->video_ctx->err_recognition = AV_EF_IGNORE_ERR | |
|
AV_EF_BITSTREAM | |
|
AV_EF_BUFFER; |
|
- p->video_stream->codec->workaround_bugs = FF_BUG_AUTODETECT; |
|
+ p->video_ctx->workaround_bugs = FF_BUG_AUTODETECT; |
|
|
|
|
|
- if (avcodec_open2 (p->video_stream->codec, p->video_codec, NULL) < 0) |
|
+ if (avcodec_open2 (p->video_ctx, p->video_codec, NULL) < 0) |
|
{ |
|
- g_warning ("error opening codec %s", p->video_stream->codec->codec->name); |
|
+ g_warning ("error opening codec %s", p->video_ctx->codec->name); |
|
return; |
|
} |
|
} |
|
@@ -485,10 +535,20 @@ prepare (GeglOperation *operation) |
|
{ |
|
p->audio_codec = avcodec_find_decoder (p->audio_stream->codecpar->codec_id); |
|
if (p->audio_codec == NULL) |
|
- g_warning ("audio codec not found"); |
|
- else if (avcodec_open2 (p->audio_stream->codec, p->audio_codec, NULL) < 0) |
|
{ |
|
- g_warning ("error opening codec %s", p->audio_stream->codec->codec->name); |
|
+ g_warning ("audio codec not found"); |
|
+ p->audio_ctx = NULL; |
|
+ return; |
|
+ } |
|
+ p->audio_ctx = avcodec_alloc_context3 (p->audio_codec); |
|
+ if (avcodec_parameters_to_context (p->audio_ctx, p->audio_stream->codecpar) < 0) |
|
+ { |
|
+ fprintf (stderr, "cannot copy audio codec parameters\n"); |
|
+ return; |
|
+ } |
|
+ if (avcodec_open2 (p->audio_ctx, p->audio_codec, NULL) < 0) |
|
+ { |
|
+ g_warning ("error opening codec %s", p->audio_ctx->codec->name); |
|
} |
|
else |
|
{ |
|
@@ -544,7 +604,7 @@ prepare (GeglOperation *operation) |
|
fprintf (stdout, "duration: %02i:%02i:%02i\n", h, m, s); |
|
} |
|
#endif |
|
- p->codec_delay = p->video_stream->codec->delay; |
|
+ p->codec_delay = p->video_ctx->delay; |
|
|
|
if (!strcmp (o->video_codec, "mpeg1video")) |
|
p->codec_delay = 1; |
|
@@ -736,7 +796,7 @@ process (GeglOperation *operation, |
|
if (p->video_stream == NULL) |
|
return TRUE; |
|
|
|
- if (p->video_stream->codec->pix_fmt == AV_PIX_FMT_RGB24) |
|
+ if (p->video_ctx->pix_fmt == AV_PIX_FMT_RGB24) |
|
{ |
|
GeglRectangle extent = {0,0,p->width,p->height}; |
|
gegl_buffer_set (output, &extent, 0, babl_format("R'G'B' u8"), p->lavc_frame->data[0], GEGL_AUTO_ROWSTRIDE); |
|
@@ -746,7 +806,7 @@ process (GeglOperation *operation, |
|
struct SwsContext *img_convert_ctx; |
|
GeglRectangle extent = {0,0,p->width,p->height}; |
|
|
|
- img_convert_ctx = sws_getContext(p->width, p->height, p->video_stream->codec->pix_fmt, |
|
+ img_convert_ctx = sws_getContext(p->width, p->height, p->video_ctx->pix_fmt, |
|
p->width, p->height, AV_PIX_FMT_RGB24, |
|
SWS_BICUBIC, NULL, NULL, NULL); |
|
if (!p->rgb_frame) |
|
diff --git a/operations/external/ff-save.c b/operations/external/ff-save.c |
|
index 8dfb3ee89894d8f1d7c73496775c95520082467f..320ad029b59ac5066852cb3a1430c6016c084072 100644 |
|
--- a/operations/external/ff-save.c |
|
+++ b/operations/external/ff-save.c |
|
@@ -82,6 +82,8 @@ property_int (me_subpel_quality, _("me-subpel-quality"), 0) |
|
|
|
#include "gegl-op.h" |
|
|
|
+#include <libavutil/channel_layout.h> |
|
+#include <libavutil/imgutils.h> |
|
#include <libavformat/avformat.h> |
|
#include <libavcodec/avcodec.h> |
|
#include <libavutil/avutil.h> |
|
@@ -106,6 +108,7 @@ typedef struct |
|
AVOutputFormat *fmt; |
|
AVFormatContext *oc; |
|
AVStream *video_st; |
|
+ AVCodecContext *video_ctx; |
|
|
|
AVFrame *picture, *tmp_picture; |
|
uint8_t *video_outbuf; |
|
@@ -117,6 +120,7 @@ typedef struct |
|
* using gggl directly,. without needing to link with the oxide library |
|
*/ |
|
AVStream *audio_st; |
|
+ AVCodecContext *audio_ctx; |
|
|
|
uint32_t sample_rate; |
|
uint32_t bits; |
|
@@ -247,8 +251,6 @@ init (GeglProperties *o) |
|
|
|
if (!inited) |
|
{ |
|
- av_register_all (); |
|
- avcodec_register_all (); |
|
inited = 1; |
|
} |
|
|
|
@@ -282,7 +284,7 @@ static void write_audio_frame (GeglProperties *o, |
|
static AVStream * |
|
add_audio_stream (GeglProperties *o, AVFormatContext * oc, int codec_id) |
|
{ |
|
- AVCodecContext *c; |
|
+ AVCodecParameters *cp; |
|
AVStream *st; |
|
|
|
st = avformat_new_stream (oc, NULL); |
|
@@ -292,12 +294,26 @@ add_audio_stream (GeglProperties *o, AVFormatContext * oc, int codec_id) |
|
exit (1); |
|
} |
|
|
|
- c = st->codec; |
|
- c->codec_id = codec_id; |
|
- c->codec_type = AVMEDIA_TYPE_AUDIO; |
|
+ cp = st->codecpar; |
|
+ cp->codec_id = codec_id; |
|
+ cp->codec_type = AVMEDIA_TYPE_AUDIO; |
|
+ cp->bit_rate = o->audio_bit_rate * 1000; |
|
|
|
- if (oc->oformat->flags & AVFMT_GLOBALHEADER) |
|
- c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
|
+ if (o->audio_sample_rate == -1) |
|
+ { |
|
+ if (o->audio) |
|
+ { |
|
+ if (gegl_audio_fragment_get_sample_rate (o->audio) == 0) |
|
+ { |
|
+ gegl_audio_fragment_set_sample_rate (o->audio, 48000); // XXX: should skip adding audiostream instead |
|
+ } |
|
+ o->audio_sample_rate = gegl_audio_fragment_get_sample_rate (o->audio); |
|
+ } |
|
+ } |
|
+ cp->sample_rate = o->audio_sample_rate; |
|
+ |
|
+ cp->channel_layout = AV_CH_LAYOUT_STEREO; |
|
+ cp->channels = 2; |
|
|
|
return st; |
|
} |
|
@@ -306,49 +322,44 @@ add_audio_stream (GeglProperties *o, AVFormatContext * oc, int codec_id) |
|
static gboolean |
|
open_audio (GeglProperties *o, AVFormatContext * oc, AVStream * st) |
|
{ |
|
+ Priv *p = (Priv*)o->user_data; |
|
AVCodecContext *c; |
|
- AVCodec *codec; |
|
+ AVCodecParameters *cp; |
|
+ const AVCodec *codec; |
|
int i; |
|
|
|
- c = st->codec; |
|
+ cp = st->codecpar; |
|
|
|
/* find the audio encoder */ |
|
- codec = avcodec_find_encoder (c->codec_id); |
|
+ codec = avcodec_find_encoder (cp->codec_id); |
|
if (!codec) |
|
{ |
|
+ p->audio_ctx = NULL; |
|
fprintf (stderr, "codec not found\n"); |
|
return FALSE; |
|
} |
|
- c->bit_rate = o->audio_bit_rate * 1000; |
|
- c->sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP; |
|
- |
|
- if (o->audio_sample_rate == -1) |
|
- { |
|
- if (o->audio) |
|
+ p->audio_ctx = c = avcodec_alloc_context3 (codec); |
|
+ cp->format = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP; |
|
+ if (codec->supported_samplerates) |
|
{ |
|
- if (gegl_audio_fragment_get_sample_rate (o->audio) == 0) |
|
- { |
|
- gegl_audio_fragment_set_sample_rate (o->audio, 48000); // XXX: should skip adding audiostream instead |
|
- } |
|
- o->audio_sample_rate = gegl_audio_fragment_get_sample_rate (o->audio); |
|
+ for (i = 0; codec->supported_samplerates[i]; i++) |
|
+ { |
|
+ if (codec->supported_samplerates[i] == cp->sample_rate) |
|
+ break; |
|
+ } |
|
+ if (!codec->supported_samplerates[i]) |
|
+ cp->sample_rate = codec->supported_samplerates[0]; |
|
} |
|
- } |
|
- c->sample_rate = o->audio_sample_rate; |
|
- c->channel_layout = AV_CH_LAYOUT_STEREO; |
|
- c->channels = 2; |
|
- |
|
- |
|
- if (codec->supported_samplerates) |
|
- { |
|
- c->sample_rate = codec->supported_samplerates[0]; |
|
- for (i = 0; codec->supported_samplerates[i]; i++) |
|
+ if (avcodec_parameters_to_context (c, cp) < 0) |
|
{ |
|
- if (codec->supported_samplerates[i] == o->audio_sample_rate) |
|
- c->sample_rate = o->audio_sample_rate; |
|
+ fprintf (stderr, "cannot copy codec parameters\n"); |
|
+ return FALSE; |
|
} |
|
- } |
|
- //st->time_base = (AVRational){1, c->sample_rate}; |
|
- st->time_base = (AVRational){1, o->audio_sample_rate}; |
|
+ if (p->oc->oformat->flags & AVFMT_GLOBALHEADER) |
|
+ c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
|
+ |
|
+ st->time_base = (AVRational){1, c->sample_rate}; |
|
+ //st->time_base = (AVRational){1, o->audio_sample_rate}; |
|
|
|
c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; // ffmpeg AAC is not quite stable yet |
|
|
|
@@ -358,7 +369,11 @@ open_audio (GeglProperties *o, AVFormatContext * oc, AVStream * st) |
|
fprintf (stderr, "could not open codec\n"); |
|
return FALSE; |
|
} |
|
- |
|
+ if (avcodec_parameters_from_context (cp, c) < 0) |
|
+ { |
|
+ fprintf (stderr, "cannot copy back the audio codec parameters\n"); |
|
+ return FALSE; |
|
+ } |
|
return TRUE; |
|
} |
|
|
|
@@ -393,19 +408,13 @@ static void encode_audio_fragments (Priv *p, AVFormatContext *oc, AVStream *st, |
|
{ |
|
while (p->audio_pos - p->audio_read_pos > frame_size) |
|
{ |
|
- AVCodecContext *c = st->codec; |
|
+ AVCodecContext *c = p->audio_ctx; |
|
long i; |
|
int ret; |
|
- int got_packet = 0; |
|
static AVPacket pkt = { 0 }; /* XXX: static, should be stored in instance somehow */ |
|
AVFrame *frame = alloc_audio_frame (c->sample_fmt, c->channel_layout, |
|
c->sample_rate, frame_size); |
|
|
|
- if (pkt.size == 0) |
|
- { |
|
- av_init_packet (&pkt); |
|
- } |
|
- |
|
av_frame_make_writable (frame); |
|
switch (c->sample_fmt) { |
|
case AV_SAMPLE_FMT_FLT: |
|
@@ -469,19 +478,34 @@ static void encode_audio_fragments (Priv *p, AVFormatContext *oc, AVStream *st, |
|
frame->pts = p->next_apts; |
|
p->next_apts += frame_size; |
|
|
|
- //ret = avcodec_send_frame (c, frame); |
|
- ret = avcodec_encode_audio2 (c, &pkt, frame, &got_packet); |
|
- |
|
- if (ret < 0) { |
|
- fprintf (stderr, "Error encoding audio frame: %s\n", av_err2str (ret)); |
|
- } |
|
- if (got_packet) |
|
- { |
|
- av_packet_rescale_ts (&pkt, st->codec->time_base, st->time_base); |
|
- pkt.stream_index = st->index; |
|
- av_interleaved_write_frame (oc, &pkt); |
|
- av_packet_unref (&pkt); |
|
- } |
|
+ ret = avcodec_send_frame (c, frame); |
|
+ if (ret < 0) |
|
+ { |
|
+ fprintf (stderr, "avcodec_send_frame failed: %s\n", av_err2str (ret)); |
|
+ } |
|
+ while (ret == 0) |
|
+ { |
|
+ if (pkt.size == 0) |
|
+ { |
|
+ av_init_packet (&pkt); |
|
+ } |
|
+ ret = avcodec_receive_packet (c, &pkt); |
|
+ if (ret == AVERROR(EAGAIN)) |
|
+ { |
|
+ // no more packets; should send the next frame now |
|
+ } |
|
+ else if (ret < 0) |
|
+ { |
|
+ fprintf (stderr, "avcodec_receive_packet failed: %s\n", av_err2str (ret)); |
|
+ } |
|
+ else |
|
+ { |
|
+ av_packet_rescale_ts (&pkt, c->time_base, st->time_base); |
|
+ pkt.stream_index = st->index; |
|
+ av_interleaved_write_frame (oc, &pkt); |
|
+ av_packet_unref (&pkt); |
|
+ } |
|
+ } |
|
av_frame_free (&frame); |
|
p->audio_read_pos += frame_size; |
|
} |
|
@@ -492,7 +516,7 @@ void |
|
write_audio_frame (GeglProperties *o, AVFormatContext * oc, AVStream * st) |
|
{ |
|
Priv *p = (Priv*)o->user_data; |
|
- AVCodecContext *c = st->codec; |
|
+ AVCodecContext *c = p->audio_ctx; |
|
int sample_count = 100000; |
|
|
|
if (o->audio) |
|
@@ -549,8 +573,7 @@ write_audio_frame (GeglProperties *o, AVFormatContext * oc, AVStream * st) |
|
void |
|
close_audio (Priv * p, AVFormatContext * oc, AVStream * st) |
|
{ |
|
- avcodec_close (st->codec); |
|
- |
|
+ avcodec_free_context (&p->audio_ctx); |
|
} |
|
|
|
/* add a video output stream */ |
|
@@ -559,7 +582,7 @@ add_video_stream (GeglProperties *o, AVFormatContext * oc, int codec_id) |
|
{ |
|
Priv *p = (Priv*)o->user_data; |
|
|
|
- AVCodecContext *c; |
|
+ AVCodecParameters *cp; |
|
AVStream *st; |
|
|
|
st = avformat_new_stream (oc, NULL); |
|
@@ -569,78 +592,23 @@ add_video_stream (GeglProperties *o, AVFormatContext * oc, int codec_id) |
|
exit (1); |
|
} |
|
|
|
- c = st->codec; |
|
- c->codec_id = codec_id; |
|
- c->codec_type = AVMEDIA_TYPE_VIDEO; |
|
+ cp = st->codecpar; |
|
+ cp->codec_id = codec_id; |
|
+ cp->codec_type = AVMEDIA_TYPE_VIDEO; |
|
/* put sample propeters */ |
|
- c->bit_rate = o->video_bit_rate * 1000; |
|
+ cp->bit_rate = o->video_bit_rate * 1000; |
|
#ifdef USE_FINE_GRAINED_FFMPEG |
|
- c->rc_min_rate = o->video_bit_rate_min * 1000; |
|
- c->rc_max_rate = o->video_bit_rate_max * 1000; |
|
+ cp->rc_min_rate = o->video_bit_rate_min * 1000; |
|
+ cp->rc_max_rate = o->video_bit_rate_max * 1000; |
|
if (o->video_bit_rate_tolerance >= 0) |
|
- c->bit_rate_tolerance = o->video_bit_rate_tolerance * 1000; |
|
+ cp->bit_rate_tolerance = o->video_bit_rate_tolerance * 1000; |
|
#endif |
|
/* resolution must be a multiple of two */ |
|
- c->width = p->width; |
|
- c->height = p->height; |
|
+ cp->width = p->width; |
|
+ cp->height = p->height; |
|
/* frames per second */ |
|
st->time_base =(AVRational){1000, o->frame_rate * 1000}; |
|
- c->time_base = st->time_base; |
|
- |
|
- c->pix_fmt = AV_PIX_FMT_YUV420P; |
|
- |
|
- if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) |
|
- { |
|
- c->max_b_frames = 2; |
|
- } |
|
- |
|
- if (c->codec_id == AV_CODEC_ID_H264) |
|
- { |
|
- c->qcompress = 0.6; // qcomp=0.6 |
|
- c->me_range = 16; // me_range=16 |
|
- c->gop_size = 250; // g=250 |
|
- c->max_b_frames = 3; // bf=3 |
|
- } |
|
- |
|
- if (o->video_bufsize) |
|
- c->rc_buffer_size = o->video_bufsize * 1000; |
|
-#if USE_FINE_GRAINED_FFMPEG |
|
- if (o->global_quality) |
|
- c->global_quality = o->global_quality; |
|
- if (o->qcompress != 0.0) |
|
- c->qcompress = o->qcompress; |
|
- if (o->qblur != 0.0) |
|
- c->qblur = o->qblur; |
|
- if (o->max_qdiff != 0) |
|
- c->max_qdiff = o->max_qdiff; |
|
- if (o->me_subpel_quality != 0) |
|
- c->me_subpel_quality = o->me_subpel_quality; |
|
- if (o->i_quant_factor != 0.0) |
|
- c->i_quant_factor = o->i_quant_factor; |
|
- if (o->i_quant_offset != 0.0) |
|
- c->i_quant_offset = o->i_quant_offset; |
|
- if (o->max_b_frames) |
|
- c->max_b_frames = o->max_b_frames; |
|
- if (o->me_range) |
|
- c->me_range = o->me_range; |
|
- if (o->noise_reduction) |
|
- c->noise_reduction = o->noise_reduction; |
|
- if (o->scenechange_threshold) |
|
- c->scenechange_threshold = o->scenechange_threshold; |
|
- if (o->trellis) |
|
- c->trellis = o->trellis; |
|
- if (o->qmin) |
|
- c->qmin = o->qmin; |
|
- if (o->qmax) |
|
- c->qmax = o->qmax; |
|
- if (o->gop_size) |
|
- c->gop_size = o->gop_size; |
|
- if (o->keyint_min) |
|
- c->keyint_min = o->keyint_min; |
|
-#endif |
|
- |
|
- if (oc->oformat->flags & AVFMT_GLOBALHEADER) |
|
- c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
|
+ cp->format = AV_PIX_FMT_YUV420P; |
|
|
|
return st; |
|
} |
|
@@ -656,14 +624,15 @@ alloc_picture (int pix_fmt, int width, int height) |
|
picture = av_frame_alloc (); |
|
if (!picture) |
|
return NULL; |
|
- size = avpicture_get_size (pix_fmt, width + 1, height + 1); |
|
+ size = av_image_get_buffer_size(pix_fmt, width + 1, height + 1, 1); |
|
picture_buf = malloc (size); |
|
if (!picture_buf) |
|
{ |
|
av_free (picture); |
|
return NULL; |
|
} |
|
- avpicture_fill ((AVPicture *) picture, picture_buf, pix_fmt, width, height); |
|
+ av_image_fill_arrays (picture->data, picture->linesize, |
|
+ picture_buf, pix_fmt, width, height, 1); |
|
return picture; |
|
} |
|
|
|
@@ -671,36 +640,99 @@ static gboolean |
|
open_video (GeglProperties *o, AVFormatContext * oc, AVStream * st) |
|
{ |
|
Priv *p = (Priv*)o->user_data; |
|
- AVCodec *codec; |
|
+ const AVCodec *codec; |
|
AVCodecContext *c; |
|
+ AVCodecParameters *cp; |
|
AVDictionary *codec_options = {0}; |
|
int ret; |
|
|
|
- c = st->codec; |
|
+ cp = st->codecpar; |
|
|
|
/* find the video encoder */ |
|
- codec = avcodec_find_encoder (c->codec_id); |
|
+ codec = avcodec_find_encoder (cp->codec_id); |
|
if (!codec) |
|
{ |
|
+ p->video_ctx = NULL; |
|
fprintf (stderr, "codec not found\n"); |
|
return FALSE; |
|
} |
|
- |
|
- if (codec->pix_fmts){ |
|
- int i = 0; |
|
- c->pix_fmt = codec->pix_fmts[0]; |
|
- while (codec->pix_fmts[i] !=-1) |
|
+ p->video_ctx = c = avcodec_alloc_context3 (codec); |
|
+ if (codec->pix_fmts) |
|
{ |
|
- if (codec->pix_fmts[i] == AV_PIX_FMT_RGB24) |
|
- c->pix_fmt = AV_PIX_FMT_RGB24; |
|
- i++; |
|
+ int i = 0; |
|
+ cp->format = codec->pix_fmts[0]; |
|
+ while (codec->pix_fmts[i] != -1) |
|
+ { |
|
+ if (codec->pix_fmts[i] == AV_PIX_FMT_RGB24) |
|
+ { |
|
+ cp->format = AV_PIX_FMT_RGB24; |
|
+ break; |
|
+ } |
|
+ i++; |
|
+ } |
|
} |
|
- } |
|
+ if (avcodec_parameters_to_context (c, cp) < 0) |
|
+ { |
|
+ fprintf (stderr, "cannot copy codec parameters\n"); |
|
+ return FALSE; |
|
+ } |
|
+ c->time_base = st->time_base; |
|
+ if (cp->codec_id == AV_CODEC_ID_MPEG2VIDEO) |
|
+ { |
|
+ c->max_b_frames = 2; |
|
+ } |
|
+ if (cp->codec_id == AV_CODEC_ID_H264) |
|
+ { |
|
+ c->qcompress = 0.6; // qcomp=0.6 |
|
+ c->me_range = 16; // me_range=16 |
|
+ c->gop_size = 250; // g=250 |
|
+ c->max_b_frames = 3; // bf=3 |
|
+ } |
|
+ if (o->video_bufsize) |
|
+ c->rc_buffer_size = o->video_bufsize * 1000; |
|
+ if (p->oc->oformat->flags & AVFMT_GLOBALHEADER) |
|
+ c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
|
+ |
|
#if 0 |
|
if (o->video_preset[0]) |
|
av_dict_set (&codec_options, "preset", o->video_preset, 0); |
|
#endif |
|
|
|
+#if USE_FINE_GRAINED_FFMPEG |
|
+ if (o->global_quality) |
|
+ c->global_quality = o->global_quality; |
|
+ if (o->qcompress != 0.0) |
|
+ c->qcompress = o->qcompress; |
|
+ if (o->qblur != 0.0) |
|
+ c->qblur = o->qblur; |
|
+ if (o->max_qdiff != 0) |
|
+ c->max_qdiff = o->max_qdiff; |
|
+ if (o->me_subpel_quality != 0) |
|
+ c->me_subpel_quality = o->me_subpel_quality; |
|
+ if (o->i_quant_factor != 0.0) |
|
+ c->i_quant_factor = o->i_quant_factor; |
|
+ if (o->i_quant_offset != 0.0) |
|
+ c->i_quant_offset = o->i_quant_offset; |
|
+ if (o->max_b_frames) |
|
+ c->max_b_frames = o->max_b_frames; |
|
+ if (o->me_range) |
|
+ c->me_range = o->me_range; |
|
+ if (o->noise_reduction) |
|
+ c->noise_reduction = o->noise_reduction; |
|
+ if (o->scenechange_threshold) |
|
+ c->scenechange_threshold = o->scenechange_threshold; |
|
+ if (o->trellis) |
|
+ c->trellis = o->trellis; |
|
+ if (o->qmin) |
|
+ c->qmin = o->qmin; |
|
+ if (o->qmax) |
|
+ c->qmax = o->qmax; |
|
+ if (o->gop_size) |
|
+ c->gop_size = o->gop_size; |
|
+ if (o->keyint_min) |
|
+ c->keyint_min = o->keyint_min; |
|
+#endif |
|
+ |
|
/* open the codec */ |
|
if ((ret = avcodec_open2 (c, codec, &codec_options)) < 0) |
|
{ |
|
@@ -739,6 +771,11 @@ open_video (GeglProperties *o, AVFormatContext * oc, AVStream * st) |
|
return FALSE; |
|
} |
|
} |
|
+ if (avcodec_parameters_from_context (cp, c) < 0) |
|
+ { |
|
+ fprintf (stderr, "cannot copy back the video codec parameters\n"); |
|
+ return FALSE; |
|
+ } |
|
|
|
return TRUE; |
|
} |
|
@@ -746,7 +783,7 @@ open_video (GeglProperties *o, AVFormatContext * oc, AVStream * st) |
|
static void |
|
close_video (Priv * p, AVFormatContext * oc, AVStream * st) |
|
{ |
|
- avcodec_close (st->codec); |
|
+ avcodec_free_context (&p->video_ctx); |
|
av_free (p->picture->data[0]); |
|
av_free (p->picture); |
|
if (p->tmp_picture) |
|
@@ -778,7 +815,7 @@ write_video_frame (GeglProperties *o, |
|
AVCodecContext *c; |
|
AVFrame *picture_ptr; |
|
|
|
- c = st->codec; |
|
+ c = p->video_ctx; |
|
|
|
if (c->pix_fmt != AV_PIX_FMT_RGB24) |
|
{ |
|
@@ -838,15 +875,34 @@ write_video_frame (GeglProperties *o, |
|
else |
|
#endif |
|
{ |
|
- /* encode the image */ |
|
- AVPacket pkt2; |
|
- int got_packet = 0; |
|
- av_init_packet(&pkt2); |
|
- pkt2.data = p->video_outbuf; |
|
- pkt2.size = p->video_outbuf_size; |
|
- |
|
- out_size = avcodec_encode_video2(c, &pkt2, picture_ptr, &got_packet); |
|
- |
|
+ // int got_packet = 0; |
|
+ int key_frame = 0; |
|
+ ret = avcodec_send_frame (c, picture_ptr); |
|
+ while (ret == 0) |
|
+ { |
|
+ /* encode the image */ |
|
+ AVPacket pkt2; |
|
+ av_init_packet(&pkt2); |
|
+ // pkt2 will use its own buffer |
|
+ // we may remove video_outbuf and video_outbuf_size too |
|
+ //pkt2.data = p->video_outbuf; |
|
+ //pkt2.size = p->video_outbuf_size; |
|
+ ret = avcodec_receive_packet (c, &pkt2); |
|
+ if (ret == AVERROR(EAGAIN)) |
|
+ { |
|
+ // no more packets |
|
+ ret = 0; |
|
+ break; |
|
+ } |
|
+ else if (ret < 0) |
|
+ { |
|
+ break; |
|
+ } |
|
+ // out_size = 0; |
|
+ // got_packet = 1; |
|
+ key_frame = !!(pkt2.flags & AV_PKT_FLAG_KEY); |
|
+ // coded_frame is removed by https://github.com/FFmpeg/FFmpeg/commit/11bc79089378a5ec00547d0f85bc152afdf30dfa |
|
+ /* |
|
if (!out_size && got_packet && c->coded_frame) |
|
{ |
|
c->coded_frame->pts = pkt2.pts; |
|
@@ -854,38 +910,32 @@ write_video_frame (GeglProperties *o, |
|
if (c->codec->capabilities & AV_CODEC_CAP_INTRA_ONLY) |
|
c->coded_frame->pict_type = AV_PICTURE_TYPE_I; |
|
} |
|
- |
|
- if (pkt2.side_data_elems > 0) |
|
- { |
|
- int i; |
|
- for (i = 0; i < pkt2.side_data_elems; i++) |
|
- av_free(pkt2.side_data[i].data); |
|
- av_freep(&pkt2.side_data); |
|
- pkt2.side_data_elems = 0; |
|
- } |
|
- |
|
- if (!out_size) |
|
- out_size = pkt2.size; |
|
- |
|
- /* if zero size, it means the image was buffered */ |
|
- if (out_size != 0) |
|
- { |
|
- AVPacket pkt; |
|
- av_init_packet (&pkt); |
|
- if (c->coded_frame->key_frame) |
|
- pkt.flags |= AV_PKT_FLAG_KEY; |
|
- pkt.stream_index = st->index; |
|
- pkt.data = p->video_outbuf; |
|
- pkt.size = out_size; |
|
- pkt.pts = picture_ptr->pts; |
|
- pkt.dts = picture_ptr->pts; |
|
- av_packet_rescale_ts (&pkt, c->time_base, st->time_base); |
|
- /* write the compressed frame in the media file */ |
|
- ret = av_write_frame (oc, &pkt); |
|
- } |
|
- else |
|
- { |
|
- ret = 0; |
|
+ */ |
|
+ if (pkt2.side_data_elems > 0) |
|
+ { |
|
+ int i; |
|
+ for (i = 0; i < pkt2.side_data_elems; i++) |
|
+ av_free(pkt2.side_data[i].data); |
|
+ av_freep(&pkt2.side_data); |
|
+ pkt2.side_data_elems = 0; |
|
+ } |
|
+ out_size = pkt2.size; |
|
+ /* if zero size, it means the image was buffered */ |
|
+ if (out_size != 0) |
|
+ { |
|
+ AVPacket pkt; |
|
+ av_init_packet (&pkt); |
|
+ if (key_frame) |
|
+ pkt.flags |= AV_PKT_FLAG_KEY; |
|
+ pkt.stream_index = st->index; |
|
+ pkt.data = pkt2.data; |
|
+ pkt.size = out_size; |
|
+ pkt.pts = picture_ptr->pts; |
|
+ pkt.dts = picture_ptr->pts; |
|
+ av_packet_rescale_ts (&pkt, c->time_base, st->time_base); |
|
+ /* write the compressed frame in the media file */ |
|
+ ret = av_write_frame (oc, &pkt); |
|
+ } |
|
} |
|
} |
|
if (ret != 0) |
|
@@ -901,17 +951,18 @@ tfile (GeglProperties *o) |
|
{ |
|
Priv *p = (Priv*)o->user_data; |
|
|
|
+ const AVOutputFormat *shared_fmt; |
|
if (strcmp (o->container_format, "auto")) |
|
- p->fmt = av_guess_format (o->container_format, o->path, NULL); |
|
+ shared_fmt = av_guess_format (o->container_format, o->path, NULL); |
|
else |
|
- p->fmt = av_guess_format (NULL, o->path, NULL); |
|
+ shared_fmt = av_guess_format (NULL, o->path, NULL); |
|
|
|
- if (!p->fmt) |
|
+ if (!shared_fmt) |
|
{ |
|
fprintf (stderr, |
|
"ff_save couldn't deduce outputformat from file extension: using MPEG.\n%s", |
|
""); |
|
- p->fmt = av_guess_format ("mpeg", NULL, NULL); |
|
+ shared_fmt = av_guess_format ("mpeg", NULL, NULL); |
|
} |
|
p->oc = avformat_alloc_context (); |
|
if (!p->oc) |
|
@@ -920,23 +971,25 @@ tfile (GeglProperties *o) |
|
return -1; |
|
} |
|
|
|
- p->oc->oformat = p->fmt; |
|
- |
|
- snprintf (p->oc->filename, sizeof (p->oc->filename), "%s", o->path); |
|
+ // The "avio_open" below fills "url" field instead of the "filename" |
|
+ // snprintf (p->oc->filename, sizeof (p->oc->filename), "%s", o->path); |
|
|
|
p->video_st = NULL; |
|
p->audio_st = NULL; |
|
|
|
+ enum AVCodecID audio_codec = shared_fmt->audio_codec; |
|
+ enum AVCodecID video_codec = shared_fmt->video_codec; |
|
if (strcmp (o->video_codec, "auto")) |
|
{ |
|
- AVCodec *codec = avcodec_find_encoder_by_name (o->video_codec); |
|
- p->fmt->video_codec = AV_CODEC_ID_NONE; |
|
+ const AVCodec *codec = avcodec_find_encoder_by_name (o->video_codec); |
|
+ video_codec = AV_CODEC_ID_NONE; |
|
if (codec) |
|
- p->fmt->video_codec = codec->id; |
|
+ video_codec = codec->id; |
|
else |
|
{ |
|
fprintf (stderr, "didn't find video encoder \"%s\"\navailable codecs: ", o->video_codec); |
|
- while ((codec = av_codec_next (codec))) |
|
+ void *opaque = NULL; |
|
+ while ((codec = av_codec_iterate (&opaque))) |
|
if (av_codec_is_encoder (codec) && |
|
avcodec_get_type (codec->id) == AVMEDIA_TYPE_VIDEO) |
|
fprintf (stderr, "%s ", codec->name); |
|
@@ -945,31 +998,36 @@ tfile (GeglProperties *o) |
|
} |
|
if (strcmp (o->audio_codec, "auto")) |
|
{ |
|
- AVCodec *codec = avcodec_find_encoder_by_name (o->audio_codec); |
|
- p->fmt->audio_codec = AV_CODEC_ID_NONE; |
|
+ const AVCodec *codec = avcodec_find_encoder_by_name (o->audio_codec); |
|
+ audio_codec = AV_CODEC_ID_NONE; |
|
if (codec) |
|
- p->fmt->audio_codec = codec->id; |
|
+ audio_codec = codec->id; |
|
else |
|
{ |
|
fprintf (stderr, "didn't find audio encoder \"%s\"\navailable codecs: ", o->audio_codec); |
|
- while ((codec = av_codec_next (codec))) |
|
+ void *opaque = NULL; |
|
+ while ((codec = av_codec_iterate (&opaque))) |
|
if (av_codec_is_encoder (codec) && |
|
avcodec_get_type (codec->id) == AVMEDIA_TYPE_AUDIO) |
|
fprintf (stderr, "%s ", codec->name); |
|
fprintf (stderr, "\n"); |
|
} |
|
} |
|
+ p->fmt = av_malloc (sizeof(AVOutputFormat)); |
|
+ *(p->fmt) = *shared_fmt; |
|
+ p->fmt->video_codec = video_codec; |
|
+ p->fmt->audio_codec = audio_codec; |
|
+ p->oc->oformat = p->fmt; |
|
|
|
- if (p->fmt->video_codec != AV_CODEC_ID_NONE) |
|
+ if (video_codec != AV_CODEC_ID_NONE) |
|
{ |
|
- p->video_st = add_video_stream (o, p->oc, p->fmt->video_codec); |
|
+ p->video_st = add_video_stream (o, p->oc, video_codec); |
|
} |
|
- if (p->fmt->audio_codec != AV_CODEC_ID_NONE) |
|
+ if (audio_codec != AV_CODEC_ID_NONE) |
|
{ |
|
- p->audio_st = add_audio_stream (o, p->oc, p->fmt->audio_codec); |
|
+ p->audio_st = add_audio_stream (o, p->oc, audio_codec); |
|
} |
|
|
|
- |
|
if (p->video_st && ! open_video (o, p->oc, p->video_st)) |
|
return -1; |
|
|
|
@@ -997,25 +1055,35 @@ static void flush_audio (GeglProperties *o) |
|
{ |
|
Priv *p = (Priv*)o->user_data; |
|
AVPacket pkt = { 0 }; |
|
- int ret; |
|
+ int ret = 0; |
|
|
|
- int got_packet = 0; |
|
if (!p->audio_st) |
|
return; |
|
|
|
- got_packet = 0; |
|
- av_init_packet (&pkt); |
|
- ret = avcodec_encode_audio2 (p->audio_st->codec, &pkt, NULL, &got_packet); |
|
+ ret = avcodec_send_frame (p->audio_ctx, NULL); |
|
if (ret < 0) |
|
- { |
|
- fprintf (stderr, "audio enc trouble\n"); |
|
- } |
|
- if (got_packet) |
|
{ |
|
- pkt.stream_index = p->audio_st->index; |
|
- av_packet_rescale_ts (&pkt, p->audio_st->codec->time_base, p->audio_st->time_base); |
|
- av_interleaved_write_frame (p->oc, &pkt); |
|
- av_packet_unref (&pkt); |
|
+ fprintf (stderr, "avcodec_send_frame failed while entering to draining mode: %s\n", av_err2str (ret)); |
|
+ } |
|
+ av_init_packet (&pkt); |
|
+ while (ret == 0) |
|
+ { |
|
+ ret = avcodec_receive_packet (p->audio_ctx, &pkt); |
|
+ if (ret == AVERROR_EOF) |
|
+ { |
|
+ // no more packets |
|
+ } |
|
+ else if (ret < 0) |
|
+ { |
|
+ fprintf (stderr, "avcodec_receive_packet failed: %s\n", av_err2str (ret)); |
|
+ } |
|
+ else |
|
+ { |
|
+ pkt.stream_index = p->audio_st->index; |
|
+ av_packet_rescale_ts (&pkt, p->audio_ctx->time_base, p->audio_st->time_base); |
|
+ av_interleaved_write_frame (p->oc, &pkt); |
|
+ av_packet_unref (&pkt); |
|
+ } |
|
} |
|
} |
|
|
|
@@ -1062,27 +1130,35 @@ process (GeglOperation *operation, |
|
static void flush_video (GeglProperties *o) |
|
{ |
|
Priv *p = (Priv*)o->user_data; |
|
- int got_packet = 0; |
|
long ts = p->frame_count; |
|
- do { |
|
- AVPacket pkt = { 0 }; |
|
- int ret; |
|
- got_packet = 0; |
|
- av_init_packet (&pkt); |
|
- ret = avcodec_encode_video2 (p->video_st->codec, &pkt, NULL, &got_packet); |
|
- if (ret < 0) |
|
- return; |
|
- |
|
- if (got_packet) |
|
- { |
|
- pkt.stream_index = p->video_st->index; |
|
- pkt.pts = ts; |
|
- pkt.dts = ts++; |
|
- av_packet_rescale_ts (&pkt, p->video_st->codec->time_base, p->video_st->time_base); |
|
- av_interleaved_write_frame (p->oc, &pkt); |
|
- av_packet_unref (&pkt); |
|
- } |
|
- } while (got_packet); |
|
+ AVPacket pkt = { 0 }; |
|
+ int ret = 0; |
|
+ ret = avcodec_send_frame (p->video_ctx, NULL); |
|
+ if (ret < 0) |
|
+ { |
|
+ fprintf (stderr, "avcodec_send_frame failed while entering to draining mode: %s\n", av_err2str (ret)); |
|
+ } |
|
+ av_init_packet (&pkt); |
|
+ while (ret == 0) |
|
+ { |
|
+ ret = avcodec_receive_packet (p->video_ctx, &pkt); |
|
+ if (ret == AVERROR_EOF) |
|
+ { |
|
+ // no more packets |
|
+ } |
|
+ else if (ret < 0) |
|
+ { |
|
+ } |
|
+ else |
|
+ { |
|
+ pkt.stream_index = p->video_st->index; |
|
+ pkt.pts = ts; |
|
+ pkt.dts = ts++; |
|
+ av_packet_rescale_ts (&pkt, p->video_ctx->time_base, p->video_st->time_base); |
|
+ av_interleaved_write_frame (p->oc, &pkt); |
|
+ av_packet_unref (&pkt); |
|
+ } |
|
+ } |
|
} |
|
|
|
static void |
|
@@ -1107,6 +1183,7 @@ finalize (GObject *object) |
|
} |
|
|
|
avio_closep (&p->oc->pb); |
|
+ av_freep (&p->fmt); |
|
avformat_free_context (p->oc); |
|
|
|
g_clear_pointer (&o->user_data, g_free);
|
|
|