Compare commits

...

4 Commits

Author SHA1 Message Date
57687bdfcd Write header file with correct extradata
When recording, the header must be written with extradata set to the
content of the very first packet.

Suggested-by: Steve Lhomme <robux4@ycbcr.xyz>
2019-02-09 12:54:12 +01:00
ee3cba57a8 Forward FFmpeg logs
FFmpeg logs can be useful to understand the cause of issues.
2019-02-09 12:27:13 +01:00
c11905b860 Add log verbose macro
This was the only log priority missing.
2019-02-09 12:27:13 +01:00
1a5ba59504 Fix memory leak on close
The buffer associated to the AVIOContext must be freed.
2019-02-09 12:27:13 +01:00
5 changed files with 92 additions and 16 deletions

View File

@ -284,7 +284,8 @@ run_quit:
run_finally_close_input:
avformat_close_input(&format_ctx);
run_finally_free_avio_ctx:
av_freep(&avio_ctx);
av_free(avio_ctx->buffer);
av_free(avio_ctx);
run_finally_free_format_ctx:
avformat_free_context(format_ctx);
run_finally_close_codec:

View File

@ -3,6 +3,7 @@
#include <SDL2/SDL_log.h>
#define LOGV(...) SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGD(...) SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGI(...) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGW(...) SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)

View File

@ -5,6 +5,16 @@
#include "config.h"
#include "log.h"
// In ffmpeg/doc/APIchanges:
// 2016-04-11 - 6f69f7a / 9200514 - lavf 57.33.100 / 57.5.0 - avformat.h
// Add AVStream.codecpar, deprecate AVStream.codec.
#if (LIBAVFORMAT_VERSION_MICRO >= 100 /* FFmpeg */ && \
LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100)) \
|| (LIBAVFORMAT_VERSION_MICRO < 100 && /* Libav */ \
LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 5, 0))
# define LAVF_NEW_CODEC_API
#endif
static const AVOutputFormat *find_mp4_muxer(void) {
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 9, 100)
void *opaque = NULL;
@ -30,6 +40,7 @@ SDL_bool recorder_init(struct recorder *recorder, const char *filename,
}
recorder->declared_frame_size = declared_frame_size;
recorder->header_written = SDL_FALSE;
return SDL_TRUE;
}
@ -63,13 +74,7 @@ SDL_bool recorder_open(struct recorder *recorder, AVCodec *input_codec) {
return SDL_FALSE;
}
// In ffmpeg/doc/APIchanges:
// 2016-04-11 - 6f69f7a / 9200514 - lavf 57.33.100 / 57.5.0 - avformat.h
// Add AVStream.codecpar, deprecate AVStream.codec.
#if (LIBAVFORMAT_VERSION_MICRO >= 100 /* FFmpeg */ && \
LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100)) \
|| (LIBAVFORMAT_VERSION_MICRO < 100 && /* Libav */ \
LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 5, 0))
#ifdef LAVF_NEW_CODEC_API
ostream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
ostream->codecpar->codec_id = input_codec->id;
ostream->codecpar->format = AV_PIX_FMT_YUV420P;
@ -93,14 +98,6 @@ SDL_bool recorder_open(struct recorder *recorder, AVCodec *input_codec) {
return SDL_FALSE;
}
ret = avformat_write_header(recorder->ctx, NULL);
if (ret < 0) {
LOGE("Failed to write header to %s", recorder->filename);
avio_closep(&recorder->ctx->pb);
avformat_free_context(recorder->ctx);
return SDL_FALSE;
}
return SDL_TRUE;
}
@ -113,6 +110,46 @@ void recorder_close(struct recorder *recorder) {
avformat_free_context(recorder->ctx);
}
SDL_bool recorder_write_header(struct recorder *recorder, AVPacket *packet) {
AVStream *ostream = recorder->ctx->streams[0];
uint8_t *extradata = SDL_malloc(packet->size * sizeof(uint8_t));
if (!extradata) {
LOGC("Cannot allocate extradata");
return SDL_FALSE;
}
// copy the first packet to the extra data
memcpy(extradata, packet->data, packet->size);
#ifdef LAVF_NEW_CODEC_API
ostream->codecpar->extradata = extradata;
ostream->codecpar->extradata_size = packet->size;
#else
ostream->codec->extradata = extradata;
ostream->codec->extradata_size = packet->size;
#endif
int ret = avformat_write_header(recorder->ctx, NULL);
if (ret < 0) {
LOGE("Failed to write header to %s", recorder->filename);
SDL_free(extradata);
avio_closep(&recorder->ctx->pb);
avformat_free_context(recorder->ctx);
return SDL_FALSE;
}
return SDL_TRUE;
}
SDL_bool recorder_write(struct recorder *recorder, AVPacket *packet) {
if (!recorder->header_written) {
SDL_bool ok = recorder_write_header(recorder, packet);
if (!ok) {
return SDL_FALSE;
}
recorder->header_written = SDL_TRUE;
}
return av_write_frame(recorder->ctx, packet) >= 0;
}

View File

@ -10,6 +10,7 @@ struct recorder {
char *filename;
AVFormatContext *ctx;
struct size declared_frame_size;
SDL_bool header_written;
};
SDL_bool recorder_init(struct recorder *recoder, const char *filename,

View File

@ -139,6 +139,40 @@ static void wait_show_touches(process_t process) {
process_check_success(process, "show_touches");
}
static SDL_LogPriority sdl_priority_from_av_level(int level) {
switch (level) {
case AV_LOG_PANIC:
case AV_LOG_FATAL:
return SDL_LOG_PRIORITY_CRITICAL;
case AV_LOG_ERROR:
return SDL_LOG_PRIORITY_ERROR;
case AV_LOG_WARNING:
return SDL_LOG_PRIORITY_WARN;
case AV_LOG_INFO:
return SDL_LOG_PRIORITY_INFO;
}
// do not forward others, which are too verbose
return 0;
}
static void
av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
SDL_LogPriority priority = sdl_priority_from_av_level(level);
if (priority == 0) {
return;
}
char *local_fmt = SDL_malloc(strlen(fmt) + 10);
if (!local_fmt) {
LOGC("Cannot allocate string");
return;
}
// strcpy is safe here, the destination is large enough
strcpy(local_fmt, "[FFmpeg] ");
strcpy(local_fmt + 9, fmt);
SDL_LogMessageV(SDL_LOG_CATEGORY_VIDEO, priority, local_fmt, vl);
SDL_free(local_fmt);
}
SDL_bool scrcpy(const struct scrcpy_options *options) {
SDL_bool send_frame_meta = !!options->record_filename;
if (!server_start(&server, options->serial, options->port,
@ -203,6 +237,8 @@ SDL_bool scrcpy(const struct scrcpy_options *options) {
rec = &recorder;
}
av_log_set_callback(av_log_callback);
decoder_init(&decoder, &frames, device_socket, rec);
// now we consumed the header values, the socket receives the video stream