diff --git a/src/httpd.c b/src/httpd.c index 1a2d8751..e23f003a 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -215,7 +215,7 @@ stream_chunk_xcode_cb(int fd, short event, void *arg) st = (struct stream_ctx *)arg; - xcoded = transcode(st->xcode, st->evbuf, STREAM_CHUNK_SIZE, &dummy); + xcoded = transcode(st->evbuf, STREAM_CHUNK_SIZE, st->xcode, &dummy); if (xcoded <= 0) { if (xcoded == 0) diff --git a/src/player.c b/src/player.c index 76f009ab..8f4e6072 100644 --- a/src/player.c +++ b/src/player.c @@ -960,14 +960,14 @@ stream_read(struct player_source *ps, int len) switch (ps->data_kind) { case DATA_KIND_HTTP: - ret = transcode(ps->xcode, audio_buf, len, &icy_timer); + ret = transcode(audio_buf, len, ps->xcode, &icy_timer); if (icy_timer) metadata_check_icy(); break; case DATA_KIND_FILE: - ret = transcode(ps->xcode, audio_buf, len, &icy_timer); + ret = transcode(audio_buf, len, ps->xcode, &icy_timer); break; #ifdef HAVE_SPOTIFY_H diff --git a/src/transcode.c b/src/transcode.c index 48fb6742..d0bee27d 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -261,7 +261,7 @@ decode_stream(struct decode_ctx *ctx, AVStream *in_stream) * @out stream_index * Set to the input stream index corresponding to the packet * @in ctx Decode context - * @return 0 on success, -1 on failure (including eof) + * @return 0 if OK, < 0 on error or end of file */ static int read_packet(AVPacket *packet, AVStream **stream, unsigned int *stream_index, struct decode_ctx *ctx) @@ -295,7 +295,7 @@ read_packet(AVPacket *packet, AVStream **stream, unsigned int *stream_index, str av_strerror(ret, errmsg, 128); DPRINTF(E_WARN, L_XCODE, "Could not read frame: %s\n", errmsg); free(errmsg); - return -1; + return ret; } *packet = ctx->packet; @@ -1439,10 +1439,10 @@ transcode_decoded_free(struct decoded_frame *decoded) /* Encoding, decoding and transcoding */ -struct decoded_frame * -transcode_decode(struct decode_ctx *ctx) + +int +transcode_decode(struct decoded_frame **decoded, struct decode_ctx *ctx) { - struct decoded_frame *decoded; AVPacket packet; AVStream *in_stream; AVFrame *frame; @@ -1457,7 +1457,8 @@ transcode_decode(struct decode_ctx *ctx) if (!frame) { DPRINTF(E_LOG, L_XCODE, "Out of memory for decode frame\n"); - return NULL; + + return -1; } // Loop until we either fail or get a frame @@ -1471,11 +1472,16 @@ transcode_decode(struct decode_ctx *ctx) // with empty input until no more frames are returned DPRINTF(E_DBG, L_XCODE, "Could not read packet (eof?), will flush decoders\n"); + used = 1; got_frame = flush_decoder(frame, &in_stream, &stream_index, ctx); if (got_frame) break; + + av_frame_free(&frame); + if (ret == AVERROR_EOF) + return 0; else - goto out_error; + return -1; } // "used" will tell us how much of the packet was decoded. We may @@ -1490,13 +1496,16 @@ transcode_decode(struct decode_ctx *ctx) // so let's try MAX_BAD_PACKETS times before giving up if (used < 0) { - DPRINTF(E_WARN, L_XCODE, "Couldn't decode packet\n"); + DPRINTF(E_DBG, L_XCODE, "Couldn't decode packet\n"); retry += 1; if (retry < MAX_BAD_PACKETS) continue; - else - goto out_error; + + DPRINTF(E_LOG, L_XCODE, "Couldn't decode packet after %i retries\n", MAX_BAD_PACKETS); + + av_frame_free(&frame); + return -1; } // decoder didn't process the entire packet, so flag a resume, meaning @@ -1515,24 +1524,19 @@ transcode_decode(struct decode_ctx *ctx) // Return the decoded frame and stream index frame->pts = av_frame_get_best_effort_timestamp(frame); - decoded = malloc(sizeof(struct decoded_frame)); - if (!decoded) + *decoded = malloc(sizeof(struct decoded_frame)); + if (!*decoded) { DPRINTF(E_LOG, L_XCODE, "Out of memory for decoded result\n"); - goto out_error; + + av_frame_free(&frame); + return -1; } - decoded->frame = frame; - decoded->stream_index = stream_index; + (*decoded)->frame = frame; + (*decoded)->stream_index = stream_index; - return decoded; - - out_error: - DPRINTF(E_DBG, L_XCODE, "Decode failure - probably EOF\n"); - - av_frame_free(&frame); - - return NULL; + return used; } // Filters and encodes @@ -1574,7 +1578,7 @@ transcode_encode(struct evbuffer *evbuf, struct decoded_frame *decoded, struct e } int -transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted, int *icy_timer) +transcode(struct evbuffer *evbuf, int wanted, struct transcode_ctx *ctx, int *icy_timer) { struct decoded_frame *decoded; int processed; @@ -1583,9 +1587,9 @@ transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted, int *ic processed = 0; while (processed < wanted) { - decoded = transcode_decode(ctx->decode_ctx); - if (!decoded) - return -1; + ret = transcode_decode(&decoded, ctx->decode_ctx); + if (ret <= 0) + return ret; ret = transcode_encode(evbuf, decoded, ctx->encode_ctx); transcode_decoded_free(decoded); diff --git a/src/transcode.h b/src/transcode.h index 8d08533f..8f9a2fa1 100644 --- a/src/transcode.h +++ b/src/transcode.h @@ -56,14 +56,38 @@ void transcode_decoded_free(struct decoded_frame *decoded); // Transcoding -struct decoded_frame * -transcode_decode(struct decode_ctx *ctx); +/* Demuxes and decodes the next packet from the input. + * + * @out decoded A newly allocated struct with a pointer to the frame and the + * stream. Must be freed with transcode_decoded_free(). + * @in ctx Decode context + * @return Bytes read if OK, negative if error, 0 if EOF + */ +int +transcode_decode(struct decoded_frame **decoded, struct decode_ctx *ctx); + +/* Encodes and remuxes a frame. Also resamples if needed. + * + * @out evbuf An evbuffer filled with remuxed data + * @in frame The frame to encode, e.g. from transcode_decode + * @in wanted Bytes that the caller wants processed + * @in ctx Encode context + * @return Length of evbuf if OK, negative if error + */ int transcode_encode(struct evbuffer *evbuf, struct decoded_frame *decoded, struct encode_ctx *ctx); +/* Demuxes, decodes, encodes and remuxes the next packet from the input. + * + * @out evbuf An evbuffer filled with remuxed data + * @in wanted Bytes that the caller wants processed + * @in ctx Transcode context + * @out icy_timer True if METADATA_ICY_INTERVAL has elapsed + * @return Bytes processed if OK, negative if error, 0 if EOF + */ int -transcode(struct transcode_ctx *ctx, struct evbuffer *evbuf, int wanted, int *icy_timer); +transcode(struct evbuffer *evbuf, int wanted, struct transcode_ctx *ctx, int *icy_timer); struct decoded_frame * transcode_raw2frame(uint8_t *data, size_t size);