富贵山庄

恒者行远,思者常新

示例:new/delete 一个对象

代码

1
2
3
4
5
int main(int argc, char** argv) {
std::string* str = new std::string();
delete str;
return 0;
}

汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    0x108852450 <+0>:   pushq  %rbp
0x108852451 <+1>: movq %rsp, %rbp
0x108852454 <+4>: subq $0x30, %rsp
0x108852458 <+8>: movl $0x0, -0x4(%rbp)
0x10885245f <+15>: movl %edi, -0x8(%rbp)
0x108852462 <+18>: movq %rsi, -0x10(%rbp)
0x108852466 <+22>: movl $0x18, %edi
0x10885246b <+27>: callq 0x1088c26c6 ; symbol stub for: operator new(unsigned long)
0x108852470 <+32>: movq %rax, %rdi
0x108852473 <+35>: movq %rax, -0x20(%rbp)
0x108852477 <+39>: callq 0x1088524c0 ; std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_string at string:1725
0x10885247c <+44>: movq -0x20(%rbp), %rax
0x108852480 <+48>: movq %rax, -0x18(%rbp)
0x108852484 <+52>: movq -0x18(%rbp), %rcx
0x108852488 <+56>: cmpq $0x0, %rcx
0x10885248c <+60>: movq %rcx, -0x28(%rbp)
0x108852490 <+64>: je 0x1088524ab ; <+91> at main.cpp
0x108852496 <+70>: movq -0x28(%rbp), %rdi
0x10885249a <+74>: callq 0x1088c240e ; symbol stub for: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string()
0x10885249f <+79>: movq -0x28(%rbp), %rax
0x1088524a3 <+83>: movq %rax, %rdi
0x1088524a6 <+86>: callq 0x1088c26b4 ; symbol stub for: operator delete(void*)
0x1088524ab <+91>: xorl %eax, %eax
-> 0x1088524ad <+93>: addq $0x30, %rsp
0x1088524b1 <+97>: popq %rbp
0x1088524b2 <+98>: retq
0x1088524b3 <+99>: nopw %cs:(%rax,%rax)
0x1088524bd <+109>: nopl (%rax)
阅读全文 »

视频渲染线程

视频渲染线程实际就是main线程。

初始化

初始化SDL

1
2
3
4
5
6
7
8
// SDL初始化
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
if (SDL_Init(flags)) {
av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n",
SDL_GetError());
av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
exit(1);
}
阅读全文 »

视频解码线程

轮询

不断从Packet队列中取出一帧数据进行解码,然后将解码数据放入到Frame队列中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
for (;;) {
// 获取一帧解码数据
ret = get_video_frame(is, frame);
if (ret < 0) goto the_end;
if (!ret) continue;
...

// 根据帧率计算每帧的显示时长
duration = (frame_rate.num && frame_rate.den
? av_q2d((AVRational){frame_rate.den, frame_rate.num})
: 0);
// 将帧的PTS转换为秒
pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
// 将解码后的帧数据放入到视频原始数据队列中
ret = queue_picture(is, frame, pts, duration, frame->pkt_pos,
is->viddec.pkt_serial);
av_frame_unref(frame);
...

if (ret < 0) goto the_end;
}
阅读全文 »

由主线程创建,负责媒体文件的解复用和读取,读取的数据根据流类型放入到对应的编码数据队列中

查询流信息

创建解复用上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

// 创建解复用上下文
ic = avformat_alloc_context();
if (!ic) {
...
}
// 设置中断回调
ic->interrupt_callback.callback = decode_interrupt_cb;
// 回调函数的参数
ic->interrupt_callback.opaque = is;
...
// 打开输入
err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
...

is->ic = ic;

if (genpts) ic->flags |= AVFMT_FLAG_GENPTS;

av_format_inject_global_side_data(ic);

if (find_stream_info) {
AVDictionary **opts = setup_find_stream_info_opts(ic, codec_opts);
int orig_nb_streams = ic->nb_streams;
// 读取文件头,获取文件的流详细信息
err = avformat_find_stream_info(ic, opts);

...
}
阅读全文 »

ffplay的整体结构是由5个线程和4个队列组成、运转的(不分析字幕)。

整体结构

音视频开发之ffplay队列分析

阅读全文 »

图像的显示最终都是由显示器完成的,显示器通过接收到的颜色矩阵来进行对应的显示。而颜色矩阵的产生一般有两种,一种是通过GPU来进行渲染生成,另一种是通过CPU来进行渲染生成。其中GPU比较适合来处理这件事情,所以其效率高。(硬件加速也就是指使用GPU来进行渲染加速)

在Android平台上,GPU渲染的API有两套,一套就是OpenGL-ES,另一套就是7.0后推出的Vulkan。目前使用最多的还是OpenGL-ES。

阅读全文 »

SDL是一个跨平台的音视频渲染库,是支持Android平台的,所以可以直接使用SDL库进行音频的播放。

但是SDL库在Android平台上的实现只有一种,就是通过JNI来调用Java层的AudioTrack来进行播放。所以如果你有其它的需求不想使用SDL库,那么可以直接使用Android平台原生API来播放音频。

Android平台音频播放API

前面录制的时候讲过,Android上音频输出的API比较繁琐,有多套实现。有Java层的实现AudioTrack,也有native层实现OpenSLES,在 Android O上又推出了新的native层实现AAudio,并且提供了Oboe库,对OpenSLES和AAudio进行了封装。

阅读全文 »

FFmpeg对于Android平台的视频输入设备API有一定的支持,但是比较局限,只支持Android N以上的版本,低版本无法使用。

其原因是因为FFmpeg采用的是Android N推出的native层camera API来实现的(NDK中的libcamera2ndk.so),而并非采用JNI的方式来调用Java层camera API。

Android平台视频录制API

对于视频录制API,Android平台上有两套API实现,一套是老版的Camera1,另一套是Android L之后推出的Camera2。

Camera1使用起来较为简单,但是功能相对较少,不支持多纹理输出。Camera2的API功能上虽然更加强大,但是API设计的非常底层化,不利于理解,并且YUV_420_888的数据格式,国内各大产商在实现上留下的坑太多。

Jetpack组件中,Google推出了全新的CameraX组件,对Camera1和Camera2进行了统一的封装,使得API更加简单易用。

阅读全文 »

由于FFmpeg一直都没有支持Android平台的音频输入设备API,所以无法使用FFmpeg在Android上录制音频。

Android平台音频录制API

Android上音频输入的API比较繁琐,有多套实现。有Java层的实现AudioRecord,也有native层实现OpenSLES,在 Android O之后又推出了新的native层实现AAudio,并且提供了Oboe库,对OpenSLES和AAudio进行了封装。

下面来详细的介绍下每套API的使用

AudioRecord

AudioRecord是Android平台提供的录制音频的Java层API,使用起来非常简单。通过设置采集参数就可以创建一个AudioRecord对象,调用了start方法后,就可以开始读取数据了,通过read方法将数据读取到指定的缓冲区中,调用stop后就停止采集。

阅读全文 »

视频录制流程

前面讲解录制音频时讲过,FFmpeg对各大平台的输入和输出API进行了统一的封装,这里就不在阐述。

视频的录制相比音频的录制流程基本差不多,主要是去掉了FIFO队列的逻辑。另外对于视频帧来说,FFmpeg提供的SwsContext API处理较慢,一般不太使用,可以用libyuv库,或者使用OpenGL API用GPU来提速。

阅读全文 »
0%