OBS 源码解读——编码器

发布于:2024-05-19 ⋅ 阅读:(130) ⋅ 点赞:(0)

编码器

obs-encoder.h

主要包含
3个结构体定义:输入编码器数据;编码后数据;编码器定义
1个对外输出的注册编码器函数

输入编码器数据

/** Encoder input frame */
struct encoder_frame {
   
	/** Data for the frame/audio */
	uint8_t *data[MAX_AV_PLANES];

	/** size of each plane */
	uint32_t linesize[MAX_AV_PLANES];

	/** Number of frames (audio only) */
	uint32_t frames;

	/** Presentation timestamp */
	int64_t pts;
};

编码器输出数据

/** Encoder output packet */
struct encoder_packet {
   
	uint8_t *data; /**< Packet data */
	size_t size;   /**< Packet size */

	int64_t pts; /**< Presentation timestamp */
	int64_t dts; /**< Decode timestamp */

	int32_t timebase_num; /**< Timebase numerator */
	int32_t timebase_den; /**< Timebase denominator */

	enum obs_encoder_type type; /**< Encoder type */

	bool keyframe; /**< Is a keyframe */

	/* ---------------------------------------------------------------- */
	/* Internal video variables (will be parsed automatically) */

	/* DTS in microseconds */
	int64_t dts_usec;

	/* System DTS in microseconds */
	int64_t sys_dts_usec;

	/**
	 * Packet priority
	 *
	 * This is generally use by video encoders to specify the priority
	 * of the packet.
	 */
	int priority;

	/**
	 * Dropped packet priority
	 *
	 * If this packet needs to be dropped, the next packet must be of this
	 * priority or higher to continue transmission.
	 */
	int drop_priority;

	/** Audio track index (used with outputs) */
	size_t track_idx;

	/** Encoder from which the track originated from */
	obs_encoder_t *encoder;
};

编码器接口定义

/**
 * Encoder interface
 *
 * Encoders have a limited usage with OBS.  You are not generally supposed to
 * implement every encoder out there.  Generally, these are limited or specific
 * encoders for h264/aac for streaming and recording.  It doesn't have to be
 * *just* h264 or aac of course, but generally those are the expected encoders.
 *
 * That being said, other encoders will be kept in mind for future use.
 */
struct obs_encoder_info {
   
	/* ----------------------------------------------------------------- */
	/* Required implementation*/

	/** Specifies the named identifier of this encoder */
	const char *id;

	/** Specifies the encoder type (video or audio) */
	enum obs_encoder_type type;

	/** Specifies the codec */
	const char *codec;

	/**
	 * Gets the full translated name of this encoder
	 *
	 * @param  type_data  The type_data variable of this structure
	 * @return            Translated name of the encoder
	 */
	const char *(*get_name)(void *type_data);

	/**
	 * Creates the encoder with the specified settings
	 *
	 * @param  settings  Settings for the encoder
	 * @param  encoder   OBS encoder context
	 * @return           Data associated with this encoder context, or
	 *                   NULL if initialization failed.
	 */
	void *(*create)(obs_data_t *settings, obs_encoder_t *encoder);

	/**
	 * Destroys the encoder data
	 *
	 * @param  data  Data associated with this encoder context
	 */
	void (*destroy)(void *data);

	/**
	 * Encodes frame(s), and outputs encoded packets as they become
	 * available.
	 *
	 * @param       data             Data associated with this encoder
	 *                               context
	 * @param[in]   frame            Raw audio/video data to encode
	 * @param[out]  packet           Encoder packet output, if any
	 * @param[out]  received_packet  Set to true if a packet was received,
	 *                               false otherwise
	 * @return                       true if successful, false otherwise.
	 */
	bool (*encode)(void *data, struct encoder_frame *frame,
		       struct encoder_packet *packet, bool *received_packet);

	/** Audio encoder only:  Returns the frame size for this encoder */
	size_t (*get_frame_size)(void *data);

	/* ----------------------------------------------------------------- */
	/* Optional implementation */

	/**
	 * Gets the default settings for this encoder
	 *
	 * @param[out]  settings  Data to assign default settings to
	 */
	void (*get_defaults)(obs_data_t *settings);

	/**
	 * Gets the property information of this encoder
	 *
	 * @return         The properties data
	 */
	obs_properties_t *(*get_properties)(void *data);

	/**
	 * Updates the settings for this encoder (usually used for things like
	 * changing bitrate while active)
	 *
	 * @param  data      Data associated with this encoder context
	 * @param  settings  New settings for this encoder
	 * @return           true if successful, false otherwise
	 */
	bool (*update)(void *data, obs_data_t *settings);

	/**
	 * Returns extra data associated with this encoder (usually header)
	 *
	 * @param  data             Data associated with this encoder context
	 * @param[out]  extra_data  Pointer to receive the extra data
	 * @param[out]  size        Pointer to receive the size of the extra
	 *                          data
	 * @return                  true if extra data available, false
	 *                          otherwise
	 */
	bool (*get_extra_data)(void *data, uint8_t **extra_data, size_t *size);

	/**
	 * Gets the SEI data, if any
	 *
	 * @param       data      Data associated with this encoder context
	 * @param[out]  sei_data  Pointer to receive the SEI data
	 * @param[out]  size      Pointer to receive the SEI data size
	 * @return                true if SEI data available, false otherwise
	 */
	bool (*get_sei_data)(void *data, uint8_t **sei_data, size_t *size);

	/**
	 * Returns desired audio format and sample information
	 *
	 * @param          data  Data associated with this encoder context
	 * @param[in/out]  info  Audio format information
	 */
	void (*get_audio_info)(void *data, struct audio_convert_info *info);

	/**
	 * Returns desired video format information
	 *
	 * @param          data  Data associated with this encoder context
	 * @param[in/out]  info  Video format information
	 */
	void (*get_video_info)(void *data, struct video_scale_info *info);

	void *type_data;
	void (*free_type_data)(void *type_data);

	uint32_t caps;

	/**
	 * Gets the default settings for this encoder
	 *
	 * If get_defaults is also defined both will be called, and the first
	 * call will be to get_defaults, then to get_defaults2.
	 *
	 * @param[out]  settings  Data to assign default settings to
	 * @param[in]   typedata  Type Data
	 */
	void (*get_defaults2)(obs_data_t *settings, void *type_data);

	/**
	 * Gets the property information of this encoder
	 *
	 * @param[in]   data      Pointer from create (or null)
	 * @param[in]   typedata  Type Data
	 * @return                The properties data
	 */
	obs_properties_t *(*get_properties2)(void *data, void *type_data);

	bool (*encode_texture)(void *data, uint32_t handle, int64_t pts,
			       uint64_t lock_key, uint64_t *next_key,
			       struct encoder_packet *packet,
			       bool *received_packet);
};

对外输出的注册编码器函数

EXPORT void obs_register_encoder_s(const struct obs_encoder_info *info,
				   size_t size);

/**
 * Register an encoder definition to the current obs context.  This should be
 * used in obs_module_load.
 *
 * @param  info  Pointer to the source definition structure.
 */
#define obs_register_encoder(info) \
	obs_register_encoder_s(info, sizeof(struct obs_encoder_info))

obs-encoder.c

P.S. 函数声明在 obs.h 中

obs.h 中关于编码器的输出函数声明

/* ------------------------------------------------------------------------- */
/* Encoders */

EXPORT const char *obs_encoder_get_display_name(const char *id);

/**
 * Creates a video encoder context
 *
 * @param  id        Video encoder ID
 * @param  name      Name to assign to this context
 * @param  settings  Settings
 * @return           The video encoder context, or NULL if failed or not found.
 */
EXPORT obs_encoder_t *obs_video_encoder_create(const char *id, const char *name,
					       obs_data_t *settings,
					       obs_data_t *hotkey_data);

/**
 * Creates an audio encoder context
 *
 * @param  id        Audio Encoder ID
 * @param  name      Name to assign to this context
 * @param  settings  Settings
 * @param  mixer_idx Index of the mixer to use for this audio encoder
 * @return           The video encoder context, or NULL if failed or not found.
 */
EXPORT obs_encoder_t *obs_audio_encoder_create(const char *id, const char *name,
					       obs_data_t *settings,
					       size_t mixer_idx,
					       obs_data_t *hotkey_data);

/**
 * Adds/releases a reference to an encoder.  When the last reference is
 * released, the encoder is destroyed.
 */
OBS_EXTERNAL_DEPRECATED EXPORT void obs_encoder_addref(obs_encoder_t *encoder);
EXPORT void obs_encoder_release(obs_encoder_t *encoder);

EXPORT void obs_weak_encoder_addref(obs_weak_encoder_t *weak);
EXPORT void obs_weak_encoder_release(obs_weak_encoder_t *weak);

EXPORT obs_encoder_t *obs_encoder_get_ref(obs_encoder_t *encoder);
EXPORT obs_weak_encoder_t *obs_encoder_get_weak_encoder(obs_encoder_t *encoder);
EXPORT obs_encoder_t *obs_weak_encoder_get_encoder(obs_weak_encoder_t *weak);

EXPORT bool obs_weak_encoder_references_encoder(obs_weak_encoder_t *weak,
						obs_encoder_t *encoder);

EXPORT void obs_encoder_set_name(obs_encoder_t *encoder, const char *name);
EXPORT const char *obs_encoder_get_name(const obs_encoder_t *encoder);

/** Returns the codec of an encoder by the id */
EXPORT const char *obs_get_encoder_codec(const char *id);

/** Returns the type of an encoder by the id */
EXPORT enum obs_encoder_type obs_get_encoder_type(const char *id);

/** Returns the codec of the encoder */
EXPORT const char *obs_encoder_get_codec(const obs_encoder_t *encoder);

/** Returns the type of an encoder */
EXPORT enum obs_encoder_type obs_encoder_get_type(const obs_encoder_t *encoder);

/**
 * Sets the scaled resolution for a video encoder.  Set width and height to 0
 * to disable scaling.  If the encoder is active, this function will trigger
 * a warning, and do nothing.
 */
EXPORT void obs_encoder_set_scaled_size(obs_encoder_t *encoder, uint32_t width,
					uint32_t height);

/** For video encoders, returns true if pre-encode scaling is enabled */
EXPORT bool obs_encoder_scaling_enabled(const obs_encoder_t *encoder);

/** For video encoders, returns the width of the encoded image */
EXPORT uint32_t obs_encoder_get_width(const obs_encoder_t *encoder);

/** For video encoders, returns the height of the encoded image */
EXPORT uint32_t obs_encoder_get_height(const obs_encoder_t *encoder);

/** For audio encoders, returns the sample rate of the audio */
EXPORT uint32_t obs_encoder_get_sample_rate(const obs_encoder_t *encoder);

/** For audio encoders, returns the frame size of the audio packet */
EXPORT size_t obs_encoder_get_frame_size(const obs_encoder_t *encoder);

/**
 * Sets the preferred video format for a video encoder.  If the encoder can use
 * the format specified, it will force a conversion to that format if the
 * obs output format does not match the preferred format.
 *
 * If the format is set to VIDEO_FORMAT_NONE, will revert to the default
 * functionality of converting only when absolutely necessary.
 */
EXPORT void obs_encoder_set_preferred_video_format(obs_encoder_t *encoder,
						   enum video_format format);
EXPORT enum video_format
obs_encoder_get_preferred_video_format(const obs_encoder_t *encoder);

/** Gets the default settings for an encoder type */
EXPORT obs_data_t *obs_encoder_defaults(const char *id);
EXPORT obs_data_t *obs_encoder_get_defaults(const obs_encoder_t *encoder);

/** Returns the property list, if any.  Free with obs_properties_destroy */
EXPORT obs_properties_t *obs_get_encoder_properties(const char *id);

/**
 * Returns the property list of an existing encoder, if any.  Free with
 * obs_properties_destroy
 */
EXPORT obs_properties_t *obs_encoder_properties(const obs_encoder_t *encoder);

/**
 * Updates the settings of the encoder context.  Usually used for changing
 * bitrate while active
 */
EXPORT void obs_encoder_update(obs_encoder_t *encoder, obs_data_t *settings);

/** Gets extra data (headers) associated with this context */
EXPORT bool obs_encoder_get_extra_data(const obs_encoder_t *encoder,
				       uint8_t **extra_data, size_t *size);

/** Returns the current settings for this encoder */
EXPORT obs_data_t *obs_encoder_get_settings(const obs_encoder_t *encoder);

/** Sets the video output context to be used with this encoder */
EXPORT void obs_encoder_set_video(obs_encoder_t *encoder, video_t *video);

/** Sets the audio output context to be used with this encoder */
EXPORT void obs_encoder_set_audio(obs_encoder_t *encoder, audio_t *audio);

/**
 * Returns the video output context used with this encoder, or NULL if not
 * a video context
 */
EXPORT video_t *obs_encoder_video(const obs_encoder_t *encoder);

/**
 * Returns the audio output context used with this encoder, or NULL if not
 * a audio context
 */
EXPORT audio_t *obs_encoder_audio(const obs_encoder_t *encoder);

/** Returns true if encoder is active, false otherwise */
EXPORT bool obs_encoder_active(const obs_encoder_t *encoder);

EXPORT void *obs_encoder_get_type_data(obs_encoder_t *encoder);

EXPORT const char *obs_encoder_get_id(const obs_encoder_t *encoder);

EXPORT uint32_t obs_get_encoder_caps(const char *encoder_id);
EXPORT uint32_t obs_encoder_get_caps(const obs_encoder_t *encoder);

#ifndef SWIG
/** Duplicates an encoder packet */
OBS_DEPRECATED
EXPORT void obs_duplicate_encoder_packet(struct encoder_packet *dst,
					 const struct encoder_packet *src);

OBS_DEPRECATED
EXPORT void obs_free_encoder_packet(struct encoder_packet *packet);
#endif

EXPORT void obs_encoder_packet_ref(struct encoder_packet *dst,
				   struct encoder_packet *src);
EXPORT void obs_encoder_packet_release(struct encoder_packet *packet);

EXPORT void *obs_encoder_create_rerouted(obs_encoder_t *encoder,
					 const char *reroute_id);

/** Returns whether encoder is paused */
EXPORT bool obs_encoder_paused(const obs_encoder_t *output);

EXPORT const char *obs_encoder_get_last_error(obs_encoder_t *encoder);
EXPORT void obs_encoder_set_last_error(obs_encoder_t *encoder,
				       const char *message);

EXPORT uint64_t obs_encoder_get_pause_offset(const obs_encoder_t *encoder);

/* ------------------------------------------------------------------------- */

obs-internal.h 中内部使用的函数和结构体

/* encoders  */

struct obs_weak_encoder {
   
	struct obs_weak_ref ref;
	struct obs_encoder *encoder;
};

struct encoder_callback {
   
	bool sent_first_packet;
	void (*new_packet)(void *param, struct encoder_packet *packet);
	void *param;
};

struct obs_encoder {
   
	struct obs_context_data context;
	struct obs_encoder_info info;

	/* allows re-routing to another encoder */
	struct obs_encoder_info orig_info;

	pthread_mutex_t init_mutex;

	uint32_t samplerate;
	size_t planes;
	size_t blocksize;
	size_t framesize;
	size_t framesize_bytes;

	size_t mixer_idx;

	uint32_t scaled_width;
	uint32_t scaled_height;
	enum video_format preferred_format;

	volatile bool active;
	volatile bool paused;
	bool initialized;

	/* indicates ownership of the info.id buffer */
	bool owns_info_id;

	uint32_t timebase_num;
	uint32_t timebase_den;

	int64_t cur_pts;

	struct circlebuf audio_input_buffer[MAX_AV_PLANES];
	uint8_t *audio_output_buffer[MAX_AV_PLANES];

	/* if a video encoder is paired with an audio encoder, make it start
	 * up at the specific timestamp.  if this is the audio encoder,
	 * wait_for_video makes it wait until it's ready to sync up with
	 * video */
	bool wait_for_video;
	bool first_received;
	struct obs_encoder *paired_encoder;
	int64_t offset_usec;
	uint64_t first_raw_ts;
	uint64_t start_ts;

	pthread_mutex_t outputs_mutex;
	DARRAY(obs_output_t *) outputs;

	bool destroy_on_stop;

	/* stores the video/audio media output pointer.  video_t *or audio_t **/
	void *media;

	pthread_mutex_t callbacks_mutex;
	DARRAY(struct encoder_callback) callbacks;

	struct pause_data pause;

	const char *profile_encoder_encode_name;
	char *last_error_message;

	/* reconfigure encoder at next possible opportunity */
	bool reconfigure_requested;
};

extern struct obs_encoder_info *find_encoder(const char *id);

extern bool obs_encoder_initialize(obs_encoder_t *encoder);
extern void obs_encoder_shutdown(obs_encoder_t *encoder);

extern void obs_encoder_start(obs_encoder_t *encoder,
			      void (*new_packet)(void *param,
						 struct encoder_packet *packet),
			      void *param);
extern void obs_encoder_stop(obs_encoder_t *encoder,
			     void (*new_packet)(void *param,
						struct encoder_packet *packet),
			     void *param);

extern void obs_encoder_add_output(struct obs_encoder *encoder,
				   struct obs_output *output);
extern void obs_encoder_remove_output(struct obs_encoder *encoder,
				      struct obs_output *output);

extern bool start_gpu_encode(obs_encoder_t *encoder);
extern void stop_gpu_encode(obs_encoder_t *encoder);

extern bool do_encode(struct obs_encoder *encoder, struct encoder_frame *frame);
extern void send_off_encoder_packet(obs_encoder_t *encoder, bool success,
				    bool received, struct encoder_packet *pkt); // 把编码后数据发送到 output 中

void obs_encoder_destroy(obs_encoder_t *encoder);

DARRAY(struct obs_encoder_info) encoder_types; 表示当前注册的编码器

struct obs_core {
   
	struct obs_module *first_module;
	DARRAY(struct obs_module_path) module_paths;

	DARRAY(struct obs_source_info) source_types;
	DARRAY(struct obs_source_info) input_types;
	DARRAY(struct obs_source_info) filter_types;
	DARRAY(struct obs_source_info) transition_types;
	DARRAY(struct obs_output_info) output_types;
	DARRAY(struct obs_encoder_info) encoder_types;
	DARRAY(struct obs_service_info) service_types;
	DARRAY(struct obs_modal_ui) modal_ui_callbacks;
	DARRAY(