#ifndef __TRANSCODE_H__ #define __TRANSCODE_H__ #include #include "http.h" #include "misc.h" enum transcode_profile { // Used for errors XCODE_UNKNOWN, // No transcoding, send as-is XCODE_NONE, // Decodes the best audio stream into PCM16 or PCM24, no resampling (does not add wav header) XCODE_PCM_NATIVE, // Decodes/resamples the best audio stream into PCM16 (with wav header) XCODE_WAV, // Decodes/resamples the best audio stream into PCM16/24/32 (no wav headers) XCODE_PCM16, XCODE_PCM24, XCODE_PCM32, // Transcodes the best audio stream to MP3 XCODE_MP3, // Transcodes the best audio stream to raw OPUS (no container) XCODE_OPUS, // Transcodes the best audio stream to raw ALAC (no container) XCODE_ALAC, // Transcodes the best audio stream to ALAC in a MP4 container XCODE_MP4_ALAC, // Produces just the header for a MP4 container with ALAC XCODE_MP4_ALAC_HEADER, // Transcodes the best audio stream from OGG XCODE_OGG, // Transcodes the best video stream to JPEG/PNG/VP8 XCODE_JPEG, XCODE_PNG, XCODE_VP8, }; enum transcode_seek_type { XCODE_SEEK_SIZE, XCODE_SEEK_SET, XCODE_SEEK_CUR, }; typedef void transcode_frame; typedef int64_t(*transcode_seekfn)(void *arg, int64_t offset, enum transcode_seek_type seek_type); struct decode_ctx; struct encode_ctx; struct transcode_ctx { struct decode_ctx *decode_ctx; struct encode_ctx *encode_ctx; }; struct transcode_evbuf_io { struct evbuffer *evbuf; // Set to null if no seek support required transcode_seekfn seekfn; void *seekfn_arg; }; struct transcode_decode_setup_args { enum transcode_profile profile; struct media_quality *quality; bool is_http; uint32_t len_ms; // Source must be either of these const char *path; struct transcode_evbuf_io *evbuf_io; }; struct transcode_encode_setup_args { enum transcode_profile profile; struct media_quality *quality; struct decode_ctx *src_ctx; struct transcode_evbuf_io *evbuf_io; struct evbuffer *prepared_header; int width; int height; }; struct transcode_metadata_string { char *type; char *codectype; char *description; char file_size[64]; char bitrate[32]; }; // Setting up struct decode_ctx * transcode_decode_setup(struct transcode_decode_setup_args args); struct encode_ctx * transcode_encode_setup(struct transcode_encode_setup_args args); struct transcode_ctx * transcode_setup(struct transcode_decode_setup_args decode_args, struct transcode_encode_setup_args encode_args); struct decode_ctx * transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality); enum transcode_profile transcode_needed(const char *user_agent, const char *client_codecs, const char *file_codectype); // Cleaning up void transcode_decode_cleanup(struct decode_ctx **ctx); void transcode_encode_cleanup(struct encode_ctx **ctx); void transcode_cleanup(struct transcode_ctx **ctx); // Transcoding /* Demuxes and decodes the next packet from the input. * * @out frame A pointer to the frame. Caller should not free it, that will * be done by the next call to the function or by the cleanup * function. * @in ctx Decode context * @return Positive if OK, negative if error, 0 if EOF */ int transcode_decode(transcode_frame **frame, struct decode_ctx *ctx); /* Encodes and remuxes a frame. Also resamples if needed. * * @out evbuf An evbuffer filled with remuxed data * @in ctx Encode context * @in frame The decoded frame to encode, e.g. from transcode_decode * @in eof If true the muxer will write a trailer to the output * @return Bytes added if OK, negative if error */ int transcode_encode(struct evbuffer *evbuf, struct encode_ctx *ctx, transcode_frame *frame, int eof); /* Demuxes, decodes, encodes and remuxes from the input. * * @out evbuf An evbuffer filled with remuxed data * @out icy_timer True if METADATA_ICY_INTERVAL has elapsed * @in ctx Transcode context * @in want_bytes Minimum number of bytes the caller wants added to the evbuffer * - set want_bytes to 0 to transcode everything until EOF/error * - set want_bytes to 1 to get one encoded packet * @return Bytes added if OK, negative if error, 0 if EOF */ int transcode(struct evbuffer *evbuf, int *icy_timer, struct transcode_ctx *ctx, int want_bytes); /* Converts a buffer with raw data to a frame that can be passed directly to the * transcode_encode() function. It does not copy, so if you free the data the * frame will become invalid. * * @in data Buffer with raw data * @in size Size of buffer * @in nsamples Number of samples in the buffer * @in quality Sample rate, bits per sample and channels * @return Opaque pointer to frame if OK, otherwise NULL */ transcode_frame * transcode_frame_new(void *data, size_t size, int nsamples, struct media_quality *quality); void transcode_frame_free(transcode_frame *frame); /* Seek to the specified position - next transcode() will return this packet * * @in ctx Transcode context * @in seek Requested seek position in ms * @return Negative if error, otherwise actual seek position */ int transcode_seek(struct transcode_ctx *ctx, int ms); /* Query for information about a media file opened by transcode_decode_setup() * * @in ctx Decode context * @in query Query - see implementation for supported queries * @return Negative if error, otherwise query dependent */ int transcode_decode_query(struct decode_ctx *ctx, const char *query); /* Query for information (e.g. sample rate) about the output being produced by * the transcoding * * @in ctx Encode context * @in query Query - see implementation for supported queries * @return Negative if error, otherwise query dependent */ int transcode_encode_query(struct encode_ctx *ctx, const char *query); // Metadata struct http_icy_metadata * transcode_metadata(struct transcode_ctx *ctx, int *changed); /* When transcoding, we are in essence serving a different source file than the * original to the client. So we can't serve some of the file metadata from the * filescanner. This function creates strings to be used for override. * * @out s Structure with (non-allocated) strings * @in profile Transcoding profile * @in q Transcoding quality * @in len_ms Length of source track */ void transcode_metadata_strings_set(struct transcode_metadata_string *s, enum transcode_profile profile, struct media_quality *q, uint32_t len_ms); /* Creates a header for later transcoding of a source file. This header can be * given to transcode_encode_setup which in some cases will make it faster (MP4) * * @out header An evbuffer with the header * @in profile Transcoding profile * @in path Path to the source file * @return Negative if error, otherwise zero */ int transcode_prepare_header(struct evbuffer **header, enum transcode_profile profile, const char *path); #endif /* !__TRANSCODE_H__ */