Refactor recorder logic
Process the initial config packet (necessary to write the header) separately.
This commit is contained in:
parent
4b246cd963
commit
f9efe48aac
2 changed files with 69 additions and 59 deletions
|
@ -93,13 +93,7 @@ sc_recorder_write_header(struct sc_recorder *recorder, const AVPacket *packet) {
|
||||||
ostream->codecpar->extradata = extradata;
|
ostream->codecpar->extradata = extradata;
|
||||||
ostream->codecpar->extradata_size = packet->size;
|
ostream->codecpar->extradata_size = packet->size;
|
||||||
|
|
||||||
int ret = avformat_write_header(recorder->ctx, NULL);
|
return avformat_write_header(recorder->ctx, NULL) >= 0;
|
||||||
if (ret < 0) {
|
|
||||||
LOGE("Failed to write header to %s", recorder->filename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -110,24 +104,6 @@ sc_recorder_rescale_packet(struct sc_recorder *recorder, AVPacket *packet) {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_recorder_write(struct sc_recorder *recorder, AVPacket *packet) {
|
sc_recorder_write(struct sc_recorder *recorder, AVPacket *packet) {
|
||||||
if (!recorder->header_written) {
|
|
||||||
if (packet->pts != AV_NOPTS_VALUE) {
|
|
||||||
LOGE("The first packet is not a config packet");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool ok = sc_recorder_write_header(recorder, packet);
|
|
||||||
if (!ok) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
recorder->header_written = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet->pts == AV_NOPTS_VALUE) {
|
|
||||||
// ignore config packets
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc_recorder_rescale_packet(recorder, packet);
|
sc_recorder_rescale_packet(recorder, packet);
|
||||||
return av_write_frame(recorder->ctx, packet) >= 0;
|
return av_write_frame(recorder->ctx, packet) >= 0;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +176,40 @@ sc_recorder_wait_video_stream(struct sc_recorder *recorder) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sc_recorder_process_header(struct sc_recorder *recorder) {
|
||||||
|
sc_mutex_lock(&recorder->mutex);
|
||||||
|
|
||||||
|
while (!recorder->stopped && sc_queue_is_empty(&recorder->queue)) {
|
||||||
|
sc_cond_wait(&recorder->queue_cond, &recorder->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recorder->stopped && sc_queue_is_empty(&recorder->queue)) {
|
||||||
|
sc_mutex_unlock(&recorder->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sc_record_packet *rec;
|
||||||
|
sc_queue_take(&recorder->queue, next, &rec);
|
||||||
|
|
||||||
|
sc_mutex_unlock(&recorder->mutex);
|
||||||
|
|
||||||
|
if (rec->packet->pts != AV_NOPTS_VALUE) {
|
||||||
|
LOGE("The first packet is not a config packet");
|
||||||
|
sc_record_packet_delete(rec);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = sc_recorder_write_header(recorder, rec->packet);
|
||||||
|
sc_record_packet_delete(rec);
|
||||||
|
if (!ok) {
|
||||||
|
LOGE("Failed to write header to %s", recorder->filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_recorder_process_packets(struct sc_recorder *recorder) {
|
sc_recorder_process_packets(struct sc_recorder *recorder) {
|
||||||
int64_t pts_origin = AV_NOPTS_VALUE;
|
int64_t pts_origin = AV_NOPTS_VALUE;
|
||||||
|
@ -208,6 +218,11 @@ sc_recorder_process_packets(struct sc_recorder *recorder) {
|
||||||
// set its duration (next_pts - current_pts)
|
// set its duration (next_pts - current_pts)
|
||||||
struct sc_record_packet *previous = NULL;
|
struct sc_record_packet *previous = NULL;
|
||||||
|
|
||||||
|
bool header_written = sc_recorder_process_header(recorder);
|
||||||
|
if (!header_written) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
sc_mutex_lock(&recorder->mutex);
|
sc_mutex_lock(&recorder->mutex);
|
||||||
|
|
||||||
|
@ -228,46 +243,43 @@ sc_recorder_process_packets(struct sc_recorder *recorder) {
|
||||||
|
|
||||||
sc_mutex_unlock(&recorder->mutex);
|
sc_mutex_unlock(&recorder->mutex);
|
||||||
|
|
||||||
if (pts_origin == AV_NOPTS_VALUE
|
if (rec->packet->pts == AV_NOPTS_VALUE) {
|
||||||
&& rec->packet->pts != AV_NOPTS_VALUE) {
|
// Ignore further config packets (e.g. on device orientation
|
||||||
// First PTS received
|
// change). The next non-config packet will have the config packet
|
||||||
pts_origin = rec->packet->pts;
|
// data prepended.
|
||||||
}
|
sc_record_packet_delete(rec);
|
||||||
|
} else {
|
||||||
|
assert(rec->packet->pts != AV_NOPTS_VALUE);
|
||||||
|
|
||||||
|
if (!previous) {
|
||||||
|
// This is the first non-config packet
|
||||||
|
assert(pts_origin == AV_NOPTS_VALUE);
|
||||||
|
pts_origin = rec->packet->pts;
|
||||||
|
rec->packet->pts = 0;
|
||||||
|
rec->packet->dts = 0;
|
||||||
|
previous = rec;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(previous);
|
||||||
|
assert(pts_origin != AV_NOPTS_VALUE);
|
||||||
|
|
||||||
if (rec->packet->pts != AV_NOPTS_VALUE) {
|
|
||||||
// Set PTS relatve to the origin
|
|
||||||
rec->packet->pts -= pts_origin;
|
rec->packet->pts -= pts_origin;
|
||||||
rec->packet->dts = rec->packet->pts;
|
rec->packet->dts = rec->packet->pts;
|
||||||
}
|
|
||||||
|
|
||||||
if (!previous) {
|
|
||||||
// we just received the first packet
|
|
||||||
previous = rec;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// config packets have no PTS, we must ignore them
|
|
||||||
if (rec->packet->pts != AV_NOPTS_VALUE
|
|
||||||
&& previous->packet->pts != AV_NOPTS_VALUE) {
|
|
||||||
// we now know the duration of the previous packet
|
// we now know the duration of the previous packet
|
||||||
previous->packet->duration =
|
previous->packet->duration =
|
||||||
rec->packet->pts - previous->packet->pts;
|
rec->packet->pts - previous->packet->pts;
|
||||||
|
|
||||||
|
bool ok = sc_recorder_write(recorder, previous->packet);
|
||||||
|
sc_record_packet_delete(previous);
|
||||||
|
if (!ok) {
|
||||||
|
LOGE("Could not record packet");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = sc_recorder_write(recorder, previous->packet);
|
|
||||||
sc_record_packet_delete(previous);
|
|
||||||
if (!ok) {
|
|
||||||
LOGE("Could not record packet");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!recorder->header_written) {
|
|
||||||
// the recorded file is empty
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the last packet
|
// Write the last packet
|
||||||
|
@ -427,7 +439,6 @@ sc_recorder_init(struct sc_recorder *recorder, const char *filename,
|
||||||
|
|
||||||
sc_queue_init(&recorder->queue);
|
sc_queue_init(&recorder->queue);
|
||||||
recorder->stopped = false;
|
recorder->stopped = false;
|
||||||
recorder->header_written = false;
|
|
||||||
|
|
||||||
recorder->codec = NULL;
|
recorder->codec = NULL;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ struct sc_recorder {
|
||||||
enum sc_record_format format;
|
enum sc_record_format format;
|
||||||
AVFormatContext *ctx;
|
AVFormatContext *ctx;
|
||||||
struct sc_size declared_frame_size;
|
struct sc_size declared_frame_size;
|
||||||
bool header_written;
|
|
||||||
|
|
||||||
sc_thread thread;
|
sc_thread thread;
|
||||||
sc_mutex mutex;
|
sc_mutex mutex;
|
||||||
|
|
Loading…
Reference in a new issue