一 libaom线程启动函数
void av1_create_workers(AV1_PRIMARY *ppi, int num_workers)
{
PrimaryMultiThreadInfo *const p_mt_info = &ppu->p_mt_info;
const AVxWorkerInterface *const = winterface = aom_get_worker_interface();
for (int i = 0; i < num_workers; ++i) {
AVxWorker* const worker = &p_mt_info->workers[i];
EncWorkerData *const thread_data = &p_mt_info->tile_thr_data[i];
winterface->init(worker);
worker->thread_nae = "aom enc worker";
thread_data->thread_id = i;
thread_data->start = i;
if (i > 0) {
if (!winterface->reset(worker))
aom_internal_error(&ppi->error, AOM_CODEC_ERROR, "Tile encoder thread creation failed");
}
}
winterface->sync(worker);
++p_mt_info->num_workers;
}
二 libaom线程调用栈
#0 in full_pixel_diamond()
#1 0x000000000058ee91 in av1_full_pixel_search ()
firstpass_inter_prediction->first_pass_motion_search
#2 0x000000000057d22c in av1_first_pass_row ()
#3 0x0000000000571124 in fp_enc_row_mt_worker_hook ()
#4 0x0000000000be5ef7 in execute ()
#5 0x00000000005788c8 in av1_fp_encode_tiles_row_mt ()
#6 0x000000000057ea03 in av1_first_pass ()
#7 0x00000000005625c0 in av1_encode ()
#8 0x0000000000c8036f in av1_encode_strategy ()
#9 0x00000000005636eb in av1_get_compressed_data ()
#10 0x00000000004ff0fb in encoder_encode ()
#11 0x00000000004bca0a in aom_codec_encode ()
#12 0x000000000040af05 in encode_frame.isra ()
#13 0x000000000040786c in main ()
三 libaom 线程调用关系
void av1_first_pass_row(AV1_COMP *cpi, ThreadData *td, TileDataEnc *tile_data, const int unit_row, const BLOCK_SIZE fp_block_size) ->
firstpass_inter_prediction(cpi, td, last_frame, golden_frame, unit_row, unit_col, recon_yoffset, recon_uvoffset, src_yoffset, fp_block_size, this_intra_error, raw_motion_err_counts, raw_motion_err_list, best_ref_mv, &best_ref_mv, &last_mv, mb_stats);
firstpass_intra_prediction()
线程入口函数
//定义一个静态的整型函数,用于多线程编码的工作钩子
static int fp_enc_row_mt_worker_hook(void *arg1, void *unused)
{
//将传入的arg1转换为EncWorkerData类型,这个结构体包含了线程的数据
EncWorkerData *const thread_data = (EncWorkerData*)arg1;
//从线程数据中获取编码器的上下文结构
AV1_COMP* const cpi = thread_data->cpi;
//获取当前线程的ID
int thread_id = thread_data->thread_id;
//获取编码器的多线程信息
AV1EncRowMultiThreadInfo *const enc_row_mt = &cpi->mt_info.enc_row_mt;
//如果配置了多线程,获取行多线程互斥锁
//获取线程数据中的内部错误信息结构体
struct aom_internal_error_info* const error_info = &thread_data->error_info;
//获取宏块解码器上下文
MACROBLOCK* const xd = &thread_data->td->mb.e_mbd;
//设置宏块解码器上下文的错误信息
xd->error_info = error_info;
//设置错误恢复环境,只有在调用setjmp()的函数中才有效
//如果setjmp() 返回非零值,表示发生了错误跳转。
if (setjmp(error_info->jmp)) {
error_info->setjmp = 0;
pthread_mutext_lock(enc_ro_mt_mutex_);
//设置firstpass_mt_exit为true, 表示第一个通过多线程退出
enc_row_mt->firstpass_mt_exit = true;
//解锁互斥锁
pthread_mutex_unlock(enc_row_mt_mutex_);
set_firstpass_encode_done(cpi);
return 0;
}
//设置setjmp字段为1,表示jmp_buf是有效的
error_info->setjmp = 1;
//获取AV1的公共结构体
AV1_COMMON *const cm = *cpi->common;
//获取当前线程对应的tile ID
int cur_tile_id = enc_row_mt->thread_id_to_tile_id[thread_id];
//断言当前tile ID不是-1
assert(cur_tile_id != -1);
//获取固定点块大小
const BLOCK_SIZE fp_block_size = cpi->fp_block_size;
//获取单位高度
const int unit_height = mi_size_high[fp_block_size];
//初始化end of frame为0
int end_of_frame = 0;
while (1) {
//初始化当前MI行
int current_mi_row = -1;
//获取firstpass_mt_exit状态
bool firstpass_mt_exit = enc_row_mt->firstpass_mt_exit;
//如果firstpass_mt_exit为false,并且没有当前tile的工作,查询其他tile的状态并获取下一个工作。
if` `(!firstpass_mt_exit &&` `!get_next_job(&cpi->tile_data[cur_tile_id],`
`¤t_mi_row, unit_height))` `{`
`// 没有当前tile的工作,查询其他tile的状态并获取下一个工作。`
`switch_tile_and_get_next_job(cm, cpi->tile_data,` `&cur_tile_id,`
`¤t_mi_row,` `&end_of_frame,` `1,`
` fp_block_size);`
`}`
`
//如果firstpass mt exit为true, 或者其他工人不需要进一步的工作,跳出循环,
if (firstpass_mt_exit || ned_of_frame) break;
//获取当前tile的数据
TileDataEnc *const this_tile = &cpi->tile_data[cur_tile_id]
// 获取行多线程同步信息。`
` AV1EncRowMultiThreadSync *const row_mt_sync =` `&this_tile->row_mt_sync;`
`// 获取线程数据。`
` ThreadData *td = thread_data->td;`
`// 断言current_mi_row不是-1,并且小于当前tile的MI行结束。`
`assert(current_mi_row !=` `-1` `&&`
` current_mi_row < this_tile->tile_info.mi_row_end);`
`// 获取单位高度的对数。`
`const` `int unit_height_log2 = mi_size_high_log2[fp_block_size];`
`// 调用av1_first_pass_row函数进行第一通过编码。`
`av1_first_pass_row(cpi, td, this_tile, current_mi_row >> unit_height_log2,`
` fp_block_size);`
`#if CONFIG_MULTITHREAD`
`// 如果配置了多线程,锁定互斥锁。`
`pthread_mutex_lock(enc_row_mt_mutex_);`
`#endif`
`// 减少正在工作的线程数。`
` row_mt_sync->num_threads_working--;`
`#if CONFIG_MULTITHREAD`
`// 解锁互斥锁。`
`pthread_mutex_unlock(enc_row_mt_mutex_);`
`#endif`
`}`
`// 重置setjmp字段为0。`
` error_info->setjmp =` `0;`
`// 返回1表示成功。`
`return` `1;`
`
}
}