spice 优化音频降低cpu

http://blog.163.com/smilexiao_11015461/blog/static/212205218201452510149544/


最近在研究Rk3066的硬解,为了怕事后忘记,特记录下来。

有软解了为什么还选择硬解,主要因为软件太耗cpu,硬解刚好补这个缺陷;

一、先看spice server这边对视频的操作,spice server是把视频流打包成mjpeg,然后通过网络传到spice client

Spice server:

Red_worker.c-red_marshall_stream_datamjpeg_encoder_start_frame(agent->mjpeg_encoder, image->u.bitmap.format,width, height,&dcc->send_data.stream_outbuf,&outbuf_size,frame_mm_time);这里把frame进行mjpeg压缩,然后red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA, NULL);发送到spice client

Spice client:

Channel-display.c-[ SPICE_MSG_DISPLAY_STREAM_DATA ]= display_handle_stream_data,所有视频数据都是在display_handle_stream_data进行处理的,然后调用display_stream_schedule(st),再到g_source_set_callback(timeout_source, (GSourceFunc)display_stream_render, (guint)st->id, NULL),回调到display_stream_render,在这里面先进行解码,然后在render

case SPICE_VIDEO_CODEC_TYPE_MJPEG:

            stream_mjpeg_data(st);

            break;

        }

我们这里主要讲解stream_mjpeg_data(st)这里面的工作;我们提供了两种解码方案:软解和硬解;

软解流程:

jpeg_read_header();//要对st->mjpeg_cinfo的成员进行赋值,网上有例子

jpeg_start_decompress();//开始解码

jpeg_read_scanlines();//一行行读取

还有memcpy();对解码后数据拷贝

jpeg_finish_decompress(&st->mjpeg_cinfo);//完成解码

 

硬解流程:

通过vpu实现硬解:

vpu_api_init(&mVpu_api, OMX_ON2_VIDEO_CodingMJPEG);//初始mjpeg解码器

decHandle = mVpu_api.get_class_On2Decoder();//获取解码器handler

mVpu_api.init_class_On2Decoder(decHandle)//初始

mVpu_api.dec_oneframe_class_On2Decoder(//开始硬解,src是数据,poutbut是硬解后的数据

            decHandle, pOutBuf, &output_len, src, &src_size);

mVpu_api.deinit_class_On2Decoder(decHandle);//释放

mVpu_api.destroy_class_On2Decoder(decHandle);

由于mjpeg流默认格式是yuv420sp,屏幕render的格式ARGB32的,所以要对解码后的数据进行格式转换;网上有yuv420sp_to_rgba的算法实现,拷贝下来就行了;这里要注意的是:解码后的数据可能被放大了,所以传到yuv420sp_to_rgba的数据要是放大的数据,frame->displaywidth,frame->height,最后就是数据拷贝了,这地方最容易出错;

if(width == frame->DisplayWidth){

memcpy(dest,tempdest,width*height*4);

}else{ uint8_t* destp = dest;

uint8_t* srcp = (uint8_t*)tempdest;

for(int i=0;i

memcpy(destp, srcp, width*4);

destp += width * 4;

srcp += frame->DisplayWidth * 4;

}

}

可悲的是,最后发现硬解的效果和软件的效果一样,cpu都要占用50%以上;

二、经过测试发现,spice client在不播视频的,只播放音频cpu都占用很高,于是又跟踪了channel-playback.c的代码:发现是音频解码库有问题libcelt051.a

channel-playback.c里面channel_set_handlers()》[ SPICE_MSG_PLAYBACK_DATA ]         = playback_handle_data,playback_handle_data把数据丢到一个线程池处理g_thread_pool_push(g_audio_pool, (gpointer)in, NULL);g_audio_pool是在spice_playback_channel_init建立的,g_audio_pool = g_thread_pool_new(audio_decode, (gpointer)channel, 1, TRUE, NULL);所有的工作都是在audio_decode里面进行的;

spice_playback_channel_init里面,spice_playback_channel_reset_capabilitiesspice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_PLAYBACK_CAP_CELT_0_5_1);client设置这个后,server每次下发的音频数据都会先通过libcelt051.a这个库进行数据压缩,然后下发。

spice server:snd_worker.c里面有snd_set_playback_compression(),这里面就会判断client 是否有SPICE_PLAYBACK_CAP_CELT_0_5_1的能力,有就压缩数据,没有就发送源数据(这个比较大,更好服务器的流量);

spice clientchannel-playback.c:audio_decode里面有对压缩方式判断,如果是SPICE_AUDIO_DATA_MODE_RAW,就直接给下层播放,如果是SPICE_AUDIO_DATA_MODE_CELT_0_5_1,就先celt051_decode,在给下层播放;

就是这个 celt051_decode 耗时间很长;找了半天没发现什么问题,原来自己用的 libcelt051.a 是直接网上下载的,最后选择下载源代码来编译,果然耗时间就短了很多, cpu 也降了 10%

你可能感兴趣的:(spice)