Pass AVCodecContext to packet sinks
Create the codec context from the demuxer, so that it can fill context data for the decoder and recorder.
This commit is contained in:
parent
4db50ddbb7
commit
4bdf632dfa
9 changed files with 52 additions and 60 deletions
|
@ -1,5 +1,6 @@
|
||||||
#include "audio_player.h"
|
#include "audio_player.h"
|
||||||
|
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavutil/opt.h>
|
#include <libavutil/opt.h>
|
||||||
|
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
|
@ -12,52 +12,20 @@
|
||||||
#define DOWNCAST(SINK) container_of(SINK, struct sc_decoder, packet_sink)
|
#define DOWNCAST(SINK) container_of(SINK, struct sc_decoder, packet_sink)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_decoder_open(struct sc_decoder *decoder, const AVCodec *codec) {
|
sc_decoder_open(struct sc_decoder *decoder, AVCodecContext *ctx) {
|
||||||
decoder->codec_ctx = avcodec_alloc_context3(codec);
|
|
||||||
if (!decoder->codec_ctx) {
|
|
||||||
LOG_OOM();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder->codec_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
|
|
||||||
|
|
||||||
if (codec->type == AVMEDIA_TYPE_VIDEO) {
|
|
||||||
// Hardcoded video properties
|
|
||||||
decoder->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
|
|
||||||
} else {
|
|
||||||
// Hardcoded audio properties
|
|
||||||
#ifdef SCRCPY_LAVU_HAS_CHLAYOUT
|
|
||||||
decoder->codec_ctx->ch_layout =
|
|
||||||
(AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO;
|
|
||||||
#else
|
|
||||||
decoder->codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
|
|
||||||
decoder->codec_ctx->channels = 2;
|
|
||||||
#endif
|
|
||||||
decoder->codec_ctx->sample_rate = 48000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) {
|
|
||||||
LOGE("Decoder '%s': could not open codec", decoder->name);
|
|
||||||
avcodec_free_context(&decoder->codec_ctx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder->frame = av_frame_alloc();
|
decoder->frame = av_frame_alloc();
|
||||||
if (!decoder->frame) {
|
if (!decoder->frame) {
|
||||||
LOG_OOM();
|
LOG_OOM();
|
||||||
avcodec_close(decoder->codec_ctx);
|
|
||||||
avcodec_free_context(&decoder->codec_ctx);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sc_frame_source_sinks_open(&decoder->frame_source,
|
if (!sc_frame_source_sinks_open(&decoder->frame_source, ctx)) {
|
||||||
decoder->codec_ctx)) {
|
|
||||||
av_frame_free(&decoder->frame);
|
av_frame_free(&decoder->frame);
|
||||||
avcodec_close(decoder->codec_ctx);
|
|
||||||
avcodec_free_context(&decoder->codec_ctx);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decoder->ctx = ctx;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +33,6 @@ static void
|
||||||
sc_decoder_close(struct sc_decoder *decoder) {
|
sc_decoder_close(struct sc_decoder *decoder) {
|
||||||
sc_frame_source_sinks_close(&decoder->frame_source);
|
sc_frame_source_sinks_close(&decoder->frame_source);
|
||||||
av_frame_free(&decoder->frame);
|
av_frame_free(&decoder->frame);
|
||||||
avcodec_close(decoder->codec_ctx);
|
|
||||||
avcodec_free_context(&decoder->codec_ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -77,7 +43,7 @@ sc_decoder_push(struct sc_decoder *decoder, const AVPacket *packet) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = avcodec_send_packet(decoder->codec_ctx, packet);
|
int ret = avcodec_send_packet(decoder->ctx, packet);
|
||||||
if (ret < 0 && ret != AVERROR(EAGAIN)) {
|
if (ret < 0 && ret != AVERROR(EAGAIN)) {
|
||||||
LOGE("Decoder '%s': could not send video packet: %d",
|
LOGE("Decoder '%s': could not send video packet: %d",
|
||||||
decoder->name, ret);
|
decoder->name, ret);
|
||||||
|
@ -85,7 +51,7 @@ sc_decoder_push(struct sc_decoder *decoder, const AVPacket *packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ret = avcodec_receive_frame(decoder->codec_ctx, decoder->frame);
|
ret = avcodec_receive_frame(decoder->ctx, decoder->frame);
|
||||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -110,9 +76,9 @@ sc_decoder_push(struct sc_decoder *decoder, const AVPacket *packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_decoder_packet_sink_open(struct sc_packet_sink *sink, const AVCodec *codec) {
|
sc_decoder_packet_sink_open(struct sc_packet_sink *sink, AVCodecContext *ctx) {
|
||||||
struct sc_decoder *decoder = DOWNCAST(sink);
|
struct sc_decoder *decoder = DOWNCAST(sink);
|
||||||
return sc_decoder_open(decoder, codec);
|
return sc_decoder_open(decoder, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -16,7 +16,7 @@ struct sc_decoder {
|
||||||
|
|
||||||
const char *name; // must be statically allocated (e.g. a string literal)
|
const char *name; // must be statically allocated (e.g. a string literal)
|
||||||
|
|
||||||
AVCodecContext *codec_ctx;
|
AVCodecContext *ctx;
|
||||||
AVFrame *frame;
|
AVFrame *frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -160,10 +160,37 @@ run_demuxer(void *data) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sc_packet_source_sinks_open(&demuxer->packet_source, codec)) {
|
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
|
||||||
|
if (!codec_ctx) {
|
||||||
|
LOG_OOM();
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
codec_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
|
||||||
|
|
||||||
|
if (codec->type == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
// Hardcoded video properties
|
||||||
|
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
|
||||||
|
} else {
|
||||||
|
// Hardcoded audio properties
|
||||||
|
#ifdef SCRCPY_LAVU_HAS_CHLAYOUT
|
||||||
|
codec_ctx->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO;
|
||||||
|
#else
|
||||||
|
codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||||
|
codec_ctx->channels = 2;
|
||||||
|
#endif
|
||||||
|
codec_ctx->sample_rate = 48000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
|
||||||
|
LOGE("Demuxer '%s': could not open codec", demuxer->name);
|
||||||
|
goto finally_free_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sc_packet_source_sinks_open(&demuxer->packet_source, codec_ctx)) {
|
||||||
|
goto finally_free_context;
|
||||||
|
}
|
||||||
|
|
||||||
// Config packets must be merged with the next non-config packet only for
|
// Config packets must be merged with the next non-config packet only for
|
||||||
// video streams
|
// video streams
|
||||||
bool must_merge_config_packet = codec->type == AVMEDIA_TYPE_VIDEO;
|
bool must_merge_config_packet = codec->type == AVMEDIA_TYPE_VIDEO;
|
||||||
|
@ -214,6 +241,9 @@ run_demuxer(void *data) {
|
||||||
av_packet_free(&packet);
|
av_packet_free(&packet);
|
||||||
finally_close_sinks:
|
finally_close_sinks:
|
||||||
sc_packet_source_sinks_close(&demuxer->packet_source);
|
sc_packet_source_sinks_close(&demuxer->packet_source);
|
||||||
|
finally_free_context:
|
||||||
|
// This also calls avcodec_close() internally
|
||||||
|
avcodec_free_context(&codec_ctx);
|
||||||
end:
|
end:
|
||||||
demuxer->cbs->on_ended(demuxer, status, demuxer->cbs_userdata);
|
demuxer->cbs->on_ended(demuxer, status, demuxer->cbs_userdata);
|
||||||
|
|
||||||
|
|
|
@ -536,9 +536,8 @@ run_recorder(void *data) {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_recorder_video_packet_sink_open(struct sc_packet_sink *sink,
|
sc_recorder_video_packet_sink_open(struct sc_packet_sink *sink,
|
||||||
const AVCodec *codec) {
|
AVCodecContext *ctx) {
|
||||||
struct sc_recorder *recorder = DOWNCAST_VIDEO(sink);
|
struct sc_recorder *recorder = DOWNCAST_VIDEO(sink);
|
||||||
assert(codec);
|
|
||||||
|
|
||||||
sc_mutex_lock(&recorder->mutex);
|
sc_mutex_lock(&recorder->mutex);
|
||||||
if (recorder->stopped) {
|
if (recorder->stopped) {
|
||||||
|
@ -546,7 +545,7 @@ sc_recorder_video_packet_sink_open(struct sc_packet_sink *sink,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
recorder->video_codec = codec;
|
recorder->video_codec = ctx->codec;
|
||||||
sc_cond_signal(&recorder->stream_cond);
|
sc_cond_signal(&recorder->stream_cond);
|
||||||
sc_mutex_unlock(&recorder->mutex);
|
sc_mutex_unlock(&recorder->mutex);
|
||||||
|
|
||||||
|
@ -601,15 +600,14 @@ sc_recorder_video_packet_sink_push(struct sc_packet_sink *sink,
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_recorder_audio_packet_sink_open(struct sc_packet_sink *sink,
|
sc_recorder_audio_packet_sink_open(struct sc_packet_sink *sink,
|
||||||
const AVCodec *codec) {
|
AVCodecContext *ctx) {
|
||||||
struct sc_recorder *recorder = DOWNCAST_AUDIO(sink);
|
struct sc_recorder *recorder = DOWNCAST_AUDIO(sink);
|
||||||
assert(recorder->audio);
|
assert(recorder->audio);
|
||||||
// only written from this thread, no need to lock
|
// only written from this thread, no need to lock
|
||||||
assert(!recorder->audio_disabled);
|
assert(!recorder->audio_disabled);
|
||||||
assert(codec);
|
|
||||||
|
|
||||||
sc_mutex_lock(&recorder->mutex);
|
sc_mutex_lock(&recorder->mutex);
|
||||||
recorder->audio_codec = codec;
|
recorder->audio_codec = ctx->codec;
|
||||||
sc_cond_signal(&recorder->stream_cond);
|
sc_cond_signal(&recorder->stream_cond);
|
||||||
sc_mutex_unlock(&recorder->mutex);
|
sc_mutex_unlock(&recorder->mutex);
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
|
|
||||||
typedef struct AVFrame AVFrame;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frame sink trait.
|
* Frame sink trait.
|
||||||
*
|
*
|
||||||
|
@ -19,6 +17,7 @@ struct sc_frame_sink {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_frame_sink_ops {
|
struct sc_frame_sink_ops {
|
||||||
|
/* The codec context is valid until the sink is closed */
|
||||||
bool (*open)(struct sc_frame_sink *sink, const AVCodecContext *ctx);
|
bool (*open)(struct sc_frame_sink *sink, const AVCodecContext *ctx);
|
||||||
void (*close)(struct sc_frame_sink *sink);
|
void (*close)(struct sc_frame_sink *sink);
|
||||||
bool (*push)(struct sc_frame_sink *sink, const AVFrame *frame);
|
bool (*push)(struct sc_frame_sink *sink, const AVFrame *frame);
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
typedef struct AVCodec AVCodec;
|
|
||||||
typedef struct AVPacket AVPacket;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Packet sink trait.
|
* Packet sink trait.
|
||||||
|
@ -19,8 +17,8 @@ struct sc_packet_sink {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_packet_sink_ops {
|
struct sc_packet_sink_ops {
|
||||||
/* The codec instance is static, it is valid until the end of the program */
|
/* The codec context is valid until the sink is closed */
|
||||||
bool (*open)(struct sc_packet_sink *sink, const AVCodec *codec);
|
bool (*open)(struct sc_packet_sink *sink, AVCodecContext *ctx);
|
||||||
void (*close)(struct sc_packet_sink *sink);
|
void (*close)(struct sc_packet_sink *sink);
|
||||||
bool (*push)(struct sc_packet_sink *sink, const AVPacket *packet);
|
bool (*push)(struct sc_packet_sink *sink, const AVPacket *packet);
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,11 @@ sc_packet_source_sinks_close_firsts(struct sc_packet_source *source,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sc_packet_source_sinks_open(struct sc_packet_source *source,
|
sc_packet_source_sinks_open(struct sc_packet_source *source,
|
||||||
const AVCodec *codec) {
|
AVCodecContext *ctx) {
|
||||||
assert(source->sink_count);
|
assert(source->sink_count);
|
||||||
for (unsigned i = 0; i < source->sink_count; ++i) {
|
for (unsigned i = 0; i < source->sink_count; ++i) {
|
||||||
struct sc_packet_sink *sink = source->sinks[i];
|
struct sc_packet_sink *sink = source->sinks[i];
|
||||||
if (!sink->ops->open(sink, codec)) {
|
if (!sink->ops->open(sink, ctx)) {
|
||||||
sc_packet_source_sinks_close_firsts(source, i);
|
sc_packet_source_sinks_close_firsts(source, i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ sc_packet_source_add_sink(struct sc_packet_source *source,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sc_packet_source_sinks_open(struct sc_packet_source *source,
|
sc_packet_source_sinks_open(struct sc_packet_source *source,
|
||||||
const AVCodec *codec);
|
AVCodecContext *ctx);
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_packet_source_sinks_close(struct sc_packet_source *source);
|
sc_packet_source_sinks_close(struct sc_packet_source *source);
|
||||||
|
|
Loading…
Reference in a new issue