-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
2087 lines (2060 loc) · 227 KB
/
atom.xml
File metadata and controls
2087 lines (2060 loc) · 227 KB
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>xfdingustc's note</title>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2017-04-06T03:29:12.595Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>xfdingustc</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>OpenMax标准协议 第二章 OpenMAX IL 介绍和框架</title>
<link href="http://yoursite.com/2017/04/01/chapter2/"/>
<id>http://yoursite.com/2017/04/01/chapter2/</id>
<published>2017-04-01T03:20:10.000Z</published>
<updated>2017-04-06T03:29:12.595Z</updated>
<content type="html"><![CDATA[<p>#OpenMAX IL 介绍和框架<br>本章介绍了OpenMAX的特点和框架</p>
<p>##2.1 OpenMAX IL 简介<br>OpenMAX IL层API定义了一个用于在系统提供的软件组件的接入层软件接口。目的是让拥有不同方法的组件提供一个标准化的接口和命令集, 来构建和销毁组件。</p>
<p>###2.1.1 架构概述<br>如果一个系统,需要四种多媒体处理模块,记为F1,F2,F3和F4。这些模块可能来自不同的公司或部门。每一个处理模块可能都有不同的初始化/销毁,配置和数据传输接口。OpenMAX IL的API可以将这些不同的接口或模块封装为标准的组件。</p>
<p>该API包括一个可以让来自不同的供应商/组织之间可以彼此交换数据的相互兼容组件的标准协议。</p>
<p>OpenMAX IL API的上层软件为IL客户端实例,可以是一个多媒体框架或是一个应用程序。IL客户端与一个称之为核心(Core)的集中式IL实例交互。 IL客户端使用OpenMAX Core进行加载和卸载组件,建立两个OpenMAX组件之间的直接通信,并且访问组件的功能方法。</p>
<p>IL客户端总是通过IL Core与组件进行通信。在大多数情况下,这种通信是通过调用IL Core的一些宏方法,这些宏可以被直接翻译为一些组件的方法。特殊情况(当IL客户端调用一个实际的核心功能)包括组件的创建,销毁以及两个组件管道的连接。</p>
<p>组件内嵌了多媒体处理功能。虽然本规范明确规定了OpenMAX Core的功能,组件供应商定义了组件的功能。组件可以操作四种类型的数据:音频,视频,图像,和其他(例如,用于同步的时间数据)。</p>
<p>一个OpenMAX组件提供了通过其组件句柄的一系列标准组件函数接口。这些函数允许客户端获取和设置组件和端口的配置参数,获取和设置组件的状态,发送命令给组件,接受事件通知,分配buffer,与单一组件端口建立通信,并连接两个组件端口之间的通信。</p>
<p>每一个OpenMAX组件应该至少有一个端口保证OpenMAX一致性。虽然供应商可能会提供一个兼容OpenMAX的组件,它没有端口。 大多数一致性测试依赖至少一个端口。OpenMAX所定义端口类型可以根据所传输的数据类型分为四类:音频、视频、图像和其他。每一个端口可以定义为为输入或者输出端口,这取决于它是否消耗或生产buffer。在一个含有四个多媒体处理功能的模块F1,F2,F3,F4的系统中,系统需要为每一个功能提供OpenMAX标准接口。开发人员可以轻易的任意组合这些功能。功能的分离是基于端口的划分。图2-1显示了这些功能的可能组合。</p>
<p><img src="img/2_1.png" alt=""></p>
<p><strong>表 2-1. OpenMAX实现的几种形式</strong></p>
<p>###2.1.2 名词解释<br>本小节介绍了OpenMax IL 中所用的字母缩写和关键词定义</p>
<p>####2.1.2.1 字母缩写<br>表2-1 列举了OpenMAX IL中首字母缩写的含义.</p>
<table>
<thead>
<tr>
<th>首字母缩写</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td>IPC</td>
<td>进程间通信</td>
</tr>
<tr>
<td>OMX</td>
<td>OpenMAX功能和结构的名称前缀。例如,一个组件可以处于OMX_StateExecuting状态。</td>
</tr>
</tbody>
</table>
<p><strong>表 2-1. 首字母缩写</strong></p>
<p>####2.1.2.2 关键词定义<br>表 2-2 列举了OpenMAX IL中关键词的定义.</p>
<table>
<thead>
<tr>
<th>关键词</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td>Accelerated component</td>
<td>OpenMAX组件封装了一部分在加速器中运行的功能。加速组件具有某些特殊的特性,如能够支持某些类型的管道(tunnel)。</td>
</tr>
<tr>
<td>Accelerator</td>
<td>硬件加速功能处理器。这种硬件模块也可称为硬件加速器。注意,加速器也可以不是硬件而是运行在另一个处理器上的软件模块。</td>
</tr>
<tr>
<td>AMR</td>
<td>自适应多媒体检索的缩写,是一种从3GGP组织提出的自适应码率编解码算法。</td>
</tr>
<tr>
<td>Host processor</td>
<td>多核系统中控制多媒体加速的处理器,通常运行高级操作系统。</td>
</tr>
<tr>
<td>IL client</td>
<td>调用OpenMAX核心(Core)或组件(component)方法的软件层。IL客户端可能是低于GUI的软件层,如Gstreamer,也可能在GUI下面几层。在此文档中,应用是指任何调用OpenMAX方法的软件模块。</td>
</tr>
<tr>
<td>Main memory</td>
<td>CPU和加速器共享的外部存储器。</td>
</tr>
<tr>
<td>OpenMAX component</td>
<td>封装目标系统所需功能的组件。OpenMAX封装了提供功能的标准接口。</td>
</tr>
<tr>
<td>OpenMAX core</td>
<td>与系统平台相关的代码,提供了找到并加载OpenMAX组件到内存的必要功能。当应用不再需要此OpenMAX组件时,Core也负责销毁内存中的组件。总的来说,加载OpenMAX组件到内存后,Core将不参与组件和应用程序之间的通信</td>
</tr>
<tr>
<td>Resource manager</td>
<td>管理系统中硬件资源的软件模块。</td>
</tr>
<tr>
<td>RTP</td>
<td>实时协议的缩写,它是用于传输实时数据的因特网标准协议,包括音频和视频。</td>
</tr>
<tr>
<td>Synchronization</td>
<td>组件之间相互控制的机制。</td>
</tr>
<tr>
<td>Tunnels/Tunneling</td>
<td>两个OpenMAX组件之间标准数据通路。</td>
</tr>
</tbody>
</table>
<p><strong>表 2-2. 关键词定义</strong></p>
<p>###2.1.3 系统组件<br>图2-2显示了使用OpenMAX进行通信的各种类型。每个组件可以有任意数量的端口用于数据通信。具有单个输出端口的组件称为源组件(Source component)。具有单个输入端口的组件称为接收器组件(sink component)。完全运行在主处理器上的组件称为主组件。在松耦合的加速器上运行的组件称为加速器组件。OpenMAX可能直接与应用程序或异构的多媒体框架集成。</p>
<p>下面描述了三种类型的通信。非通道通信(Non-tunneled)指的是IL客户端和组件之间的数据Buffer交换机制。通道(Tunneling)指的是组件之间直接交换数据Buffer的标准机制。专有通信(Proprietary)指的是两个组件之间直接信息数据通信,也可以当通道请求(tunneling request)时,作为一个两个组件通道的替代方案。</p>
<p><img src="img/2_2.png" alt=""></p>
<p><strong>表 2-2. OpenMAX IL 系统组件</strong></p>
<p>####2.1.3.1 组件Profiles<br>OpenMAX组件功能分为两个profile:base profile和interop profile。</p>
<p>Base profile 应该支持非管道(non-tunneled)通信, 可能支持专有通信(proprietary),不支持管道(tunneled)通信。</p>
<p>Interop profile是base profile的一个超集,它应该支持管道(tunneled)和非管道(non-tunneled)通信,可能支持专有通信。</p>
<p>Interop profile和base profile的主要区别是是否支持管道(tunneled)通信。定义base profile的意义在于简化OpenMAX的实现难度,因为并不需要实现tunneled 通信</p>
<p>###2.1.4 组件状态<br>每一个OpenMAX组件的运行可以视为一系列状态的转移,如图2-3。每一个组件的初始状态为unloaded。组件可以通过调用OpenMAX Core的接口进行装载。其他的状态转移可以通过直接和组件进行通信来完成。</p>
<p>当使用不正确的数据进行状态转移的时候,组件可以进入非法(invalide)状态。例如,如果回调函数的指针指向非法地址的时候,组件可能会超时并且向IL客户端发出错误警告。IL客户端检测到非法状态时, 应该停止运行,释放,卸载并且重新加载这个组件。图2-3描绘了所有的状态均可以跳转到非法状态,但非法状态只能跳转到unload状态,并且重新加载组件。</p>
<p><img src="img/2_3.png" alt=""></p>
<p><strong>表 2-3. 组件状态</strong></p>
<p>由于需要获得所需要的资源, 进入IDLE状态可能会失败。当从LOADED向IDLE转移失败时, IL客户端可以重试或者转入等待资源(Wait for resource)状态。当进入等待资源(wait for resource)状态是, 组件会向资源管理器注册,当资源可以可以获得时得到提醒。资源管理器随后将组件转至IDLE状态。IL客户端发送控制命令进行除了非法(invalide)状态以外的所以其他状态转移。</p>
<p>IDLE状态表明组件已经获得所有所需资源,但此时并没有处理数据。EXECUTING状态表明组件正在接受数据Buffer,进行处理,并且会发出响应的回调(见第3节)。PAUSE状态保持了数据buffer执行的上下文,但并不处理或交换数据或。从PAUSED到EXECUTING的状态转移可以当组件由挂起到继续时能够处理buffer。</p>
<p>从EXECLUTING到PAUSED或者IDLE的转移可能会导致处理过的buffer上下文丢失,这时候需要重新开始一个新的流。IDLE到LOADED的转可能会导致运行的资源例如通信Buffer的丢失。</p>
<p>###2.1.5 组件架构<br>表2-4描述了组件的架构。注意,该组件只有一个入口(通过一个拥有一系列标准方法接口的句柄),但可能会有多个回调,取决于组件有多少个端口(port)。每个组件会调用指定的IL客户端的事件处理程序(event handler)。每个端口(port)会调用(或回调)制定的外部方法。每个端口(port)会和一个指向buffer头的队列关联。这些buffer头指向真正的buffer。命令函数(command functions)也有一个命令队列。所有的参数或者配置函数需要提供一个指定的索引并包括一个参数或配置的结构,如图2-4。</p>
<p><img src="img/2_4.png" alt=""></p>
<p><strong>图 2-4. OpenMAX IL API 组件架构</strong></p>
<p>端口必须支持向IL客户端的回调。当组件是interop profile的时候,必须支持和其他组件之间的通信。</p>
<p>###2.1.6 通信行为<br>一旦OpenMAX core获得了组件的句柄,便可以开始对组件进行配置工作。当端口的数量被确定后,组件数据通信的方法便可以调用,并且是不可以阻塞的。<br>每一个端口会指定一个特定的数据格式,并且组件会进入合适的状态。数据通信是和组件的端口(port)绑定的。IL客户端总是会调用输入端口<code>OMX_EmptyThisBuffer</code>接口(具体信息可以看3.2.2.17小节),调用输出端口(port)的<code>OMX_FillThisBuffer</code>(具体信息可以看3.2.2.18小节)。如果是同步执行,在返回之前,回调用回调函数<code>OMX_EmptyBufferDone</code> 或 <code>OMX_FillBufferDone</code>。 图2-5表述了同步执行和异步执行的对比行为。注意, IL客户端不应该假设返回和回调的先后顺序, 必须对同步和异步的OpenMAX组件都进行异构集成。</p>
<p><img src="img/2_5.png" alt=""></p>
<p><strong>图 2-5. 异步对比同步操作</strong></p>
<p>与组件的数据通信总是指向特定的组件端口。每一个端口(port)有一个分配供使用的buffer,最小数量由组件制定。端口将buffer头与每一块buffer相关联。buffer头拥有buffer数据的引用,并且提供响应的元数据(metadata)。每个组件端口应该既可以分配自己的buffer也可以使用分配好的buffer,往往某一种方案会比其他的效率高。</p>
<p>###2.1.7 管道(tunneled) buffer的分配和共享<br>本小结描述了管道(tunnel)组件的buffer分配和共享。对于给定的管道,会有一个端口提供buffer并且将buffer转递给接受的端口。最简单的情况,提供者同时会分配这些buffer。然而,在适当的情况下,管道(tunnel)组件会选择复用buffer,以免多次内存拷贝。这种做法被称为buffer共享</p>
<p>两个端口之间的管道表示了两个端口之间的依赖关系。buffer共享扩展了这个依赖关系,使得共享同一组buffer的所有端口形成隐式依赖链。该依赖链中的一个端口分配所有的共享buffer。</p>
<p>共享buffer是在组件内部实现的,并且对其他组件透明。接受端口并不知道提供者是分配还是复用了这些buffer。此外,输出也不知道输入是否复用了这些buffer。</p>
<p>严格的说,一个组件只需要遵守他所需要的外部语义,并且实现buffer共享。更具体的说,外部语义要求一个组件能够做到如下:</p>
<ul>
<li>在所有输出端口(Provide buffer)上提供buffer。</li>
<li>精确地在其端口上传递buffer要求。</li>
<li>从一个输出端口向一个输入端口通过调用<code>OMX_EmptyThisBuffer</code>转递数据</li>
<li>从一个输入端口向一个输出端口通过调用<code>OMX_FillThisBuffer</code>返回一个buffer</li>
</ul>
<p>如果一个组件使用共享buffer, 它需要实现如下功能:</p>
<ul>
<li>在某些输出端口上提供可复用的buffer</li>
<li>当端口上有buffer通信的需求时可以共享端口。</li>
<li>调用<code>OMX_EmptyThisBuffer</code>和其对应的回调函数<code>OMX_EmptyBufferDone</code>之间, 内部会从输出端口到另一个输出端口传递一个buffer</li>
</ul>
<p>OpenMAX虽然没有明确要求组件支持共享, 但定义了外部构件语义需要兼容共享方式。本节讨论在共享buffer的上下文中实现这些语义。如果没有组件共享buffer,则实现简化为一组简单的步骤和过称。</p>
<p>####2.1.7.1 相关术语<br>本节描述了tunneled buffer的分配和共享。图2-6描绘了概念。</p>
<p><img src="img/2_6.png" alt=""></p>
<p><strong>图 2-6. Buffer分配和共享关系的例子</strong></p>
<p>在一对管道连接的端口中,端口会调用他的邻居端口<code>UseBuffer</code>接口告知自己为输出端口。输出端口并不一定需要分配内存,它可以复用同组件下另一端口的buffer。在图2-6中,端口a和c描绘了输出端口。</p>
<p>从邻居端口接收到<code>UseBuffer</code>调用的端口是一个输出端口。图2-6中的端口b和d描绘了出入端口。</p>
<p>一个端口的管道端口是指其共享管道的邻居端口。例如,在图2-6中端口b是端口a的管道端口。同理,a也是b的管道端口。</p>
<p>一个分配器端口(allocator port)是一个输出端口,而且可有分配自己的buffer。图2-6中的端口a是唯一的分配器端口。</p>
<p>共享端口(sharing port)是可以复用同一组件中其他端口buffer的端口。例如,图2-6中端口c就是共享端口。</p>
<p>一个管道组件指的是至少有一个管道的组件。</p>
<p>端口buffer的需求包括了buffer的数量和每块buffer的大小。buffer所需的最大值是指所需数量的最大值和所需大小的最大值。一个端口通过其管道端口调用<code>OMX_GetParameter</code>接口,并传入结构体<code>OMX_PORTDEFINITIONTYPE</code>参数来获得buffer的需求。注意,一个端口可能从其共享buffer的端口而不是接受<code>OMX_GetParameter</code>接口来确定其buffer的需求,因为他们隶属于同一个组件。</p>
<p>####2.1.7.2 IL客户端组建设置<br>为了配置管道组件,IL客户端需要按顺序进行下面的操作:</p>
<ol>
<li>加载所有的管道组件并配置这些组件的管道。</li>
<li>将所有的管道组件的状态由loaded转为idle。</li>
</ol>
<p>如果IL客户端没有按此进行操作,一个管道组件可能由于组件间的依赖关系而永远无法转移到idle状态。</p>
<p>####2.1.7.3 共享时组件状态由loaded到idle的转移<br>在<code>OMX_SetupTunnel</code>调用时,管道的两个端口会确立哪个端口(输入或输出)是buffer提供者。因此,当一个组件被要求从loaded转移到idle时,它会知道它所有提供者和接受者端口的角色。</p>
<p>当命令组件由loaded转移到idle的时候,它需要按顺序进行下面的操作:</p>
<ul>
<li><p>1.组件决定那种buffer共享它需要实现。如果有,需要遵循下列规则:</p>
<ul>
<li>a) 它的一个输入端口到一个或多个输出端口、一个输出端口到一个输入端口。</li>
<li>b) 只有提供者端口可以复用其他端口的buffer。</li>
<li>c) 一个组件在多个输出端口上共享buffer需要输出的端口是只读的,如图2-7所示。</li>
</ul>
</li>
</ul>
<p><img src="img/2_7.png" alt=""></p>
<p><strong>图 2-7. 可能的共享关系</strong></p>
<ul>
<li>2.组件确定哪个是其供应端口和分配器端口(如果有有的话)。如果不从同组件的非供应端口复用buffer是,一个供应端口也是一个分配端口(即,不是一个分享端口)。在图2-8中,供应端口是有箭头指向外面的端口,非供应端口是有箭头指向它的端口。端口上的箭头表明了共享关系。端口旁边的正方形(buffer)表明了这是一个分配器端口。</li>
</ul>
<p><img src="img/2_8.png" alt=""></p>
<p><strong>图 2-8. 确定分配器</strong></p>
<ul>
<li>3.组件在每个分配器端口上分配buffer的策略如下:<ul>
<li>a) 每个复用分配器端口buffer的端口,分配器端口会确定其共享端口的buffer需求。见下面的条例A。</li>
<li>b) 分配器端口通过调用<code>OMX_GetParameter</code>决定其管道端口buffer要求。参见条例B。</li>
<li>c) 分配器端口根据自己的最大需求,管道端口的要求,和所有的共享端口的要求分配buffer。</li>
<li>d) 分配器端口通过调用<code>OMX_SetParameter</code>的<code>OMX_IndexParamPortDefinition</code>设置合适的<code>nBufferCountActual</code>值,来通知非供应端口实际的buffer数量。见下面的条例E。</li>
<li>e) 分配器端口和每个复用其buffer的共享端口共享buffer。见条例D。</li>
<li>f) 每个分配的buffer,分配器端口调用其管道端口的<code>OMX_UseBuffer</code>接口。参见条例C。</li>
</ul>
</li>
</ul>
<p>组件还应遵循下列条例:</p>
<ul>
<li>A. 一个共享端口要确定其需求,共享端口应先调用其管道端口的<code>OMX_GetParameter</code>来查询需求,然后返回自己和其管道端口的最大要求。</li>
<li>B. 当一个非供应端口接受到<code>OMX_GetParameter</code>调用来查询自己的buffer需求是,它需要首先确定所有复用自己buffer的端口的需求(见条例A),然后返回自己和其他这些端口的最大值。</li>
<li>C. 当一个非供应端口接受到来自其管道端口的<code>OMX_GetParameter</code>调用,它需要把这些buffer和组件内所有和它复用buffer的端口共享。</li>
<li>D. 当端口A和组件内复用其buffer的端口B共享一个buffer时,端口B需要调用 <code>OMX_UseBuffer</code>并且将buffer传递给他的管道端口。</li>
<li>E. 当非供应端口接受到其管道端口的<code>OMX_SetParameter</code> 的<code>OMX_IndexParamPortDefinition</code>调用时,供应端口应该将值<code>nBufferCountActual</code>传递给所有复用其buffer的端口。同理,每一个通过这种方式收到 <code>nBufferCountActual</code>值的供应端口,需要通过调用传递<code>OMX_SetParameter</code> 的<code>OMX_IndexParamPortDefinition</code>的接口将<code>nBufferCount</code> 值给他的管道端口, buffer的实际数量以这种方式在整个依赖链中传播。</li>
</ul>
<p>当一个组件获得所需的所有buffer,便可以由loaded状态转为idle状态。</p>
<p>在实践中,可以有如下的直接映射:</p>
<ul>
<li>步骤1~3对应loaded向idle状态的转变</li>
<li>条例A对应一个共享端口的buffer需求的子函数</li>
<li>条例B对应<code>OMX_GetParameter</code>的实现</li>
<li>条例C对应<code>OMX_UseBuffer</code>的实现</li>
<li>条例D对应一个端口向另一个端口分享buffer的子函数</li>
</ul>
<p>为了搞清楚合理分配buffer的这些步骤和条例,可以参考图2-9.注意这个例子是用于实践上面步骤和条例的,实际的用例会负责的多。</p>
<p><img src="img/2_9.png" alt=""></p>
<p><strong>图 2-9. Buffer分配的例子</strong></p>
<p>下面集中讨论组件3如何到idle状态的,其他的组件类似。</p>
<p>当IL客户端命令组件3从loaded向idle转移时,它需要遵循下面的步骤:</p>
<ol>
<li>组件3注意到它可以重用端口d的buffer,因为端口e是一个供应者端口。组件3建立了端口d到端口e的共享关系。</li>
<li>既然端口d是一个供应者端口并且不复用buffer,那么端口d是一个分配者端口。</li>
<li>端口3分配并部署端口d的buffer:<ul>
<li>a) 既然端口e复用端口d的buffer,组件3确定端口e的需求。根据条例A, 端口e调用端口f的<code>OMX_GetParameter</code>确定f的需求,并将自己的和f的最大值报告出去。</li>
<li>b) 端口d调用端口c的<code>OMX_GetParameter</code>接口确定他的buffer需求。根据条例B,端口C需要确定端口b的buffer需求。更具提条例A,端口b返回自己和a的最大需求。端口c得到这个需求在和自己的需求比较返回最大值。</li>
<li>c) 端口d根据自己的需求和端口c,e返回的最大值分配buffer, 分配的buffer是根据端口a,b,c,d,e,f需求的最大值确定的,所有的端口都复用端口d的buffer。</li>
<li>d) 既然端口e复用端口d的buffer,组件3用端口e分享这些buffer。根据条例D,端口e调用端口f的<code>OMX_UseBuffer</code>接口以分享这些buffer。</li>
<li>e) 对于每块分配的buffer,端口d调用端口c的 <code>OMX_UseBuffer</code>。根据提条例C,端口C和B分享这些buffer。而端口b根据条例D调用端口a<code>OMX_UseBuffer</code></li>
</ul>
</li>
</ol>
<p>至此,所有组件的所有端口都有自己的buffer,所有的组件都可以转移到idle状态。</p>
<p>####2.1.7.4 使用共享buffer的协议<br>当一个输入端口收到<code>OMX_EmptyThisBuffer</code>调用得到一块共享buffer时,输入端口可以通过遵循下面的准则复用这块buffer到其共享端口:</p>
<ul>
<li>输出端口要在其管道端口的返回相应的回调函数<code>OMX_EmptyBufferDone</code>前,调用其管道端口的<code>OMX_EmptyThisBuffer</code>方法。</li>
<li>输入端口不能在所有的与其共享buffer的输出端口返回<code>OMX_EmptyBufferDone</code>之前返回<code>OMX_EmptyBufferDone</code>。</li>
</ul>
<p>####2.1.7.5 非共享情况下组件状态由loaded到idle的转移<br>如果一个组件没有共享buffer,和共享buffer的情况相比起来,组件的实现的步骤和准则会简单一些:</p>
<p>一个非共享组件要从loaded转移到idle状态时,它需要按下面的顺序进行操作:</p>
<ol>
<li>组件确定那些buffer共享需要实现。在这情况下,没有共享需要实现。</li>
<li>组件确定那些是供应端口,如果有,他们都是分配者端口。所有的供应端口都是分配者端口。</li>
<li>组件按照下面准则为所有的分配者端口分配buffer:<ul>
<li>a. 由于没有buffer共享,组件不需要获取共享端口的需求。</li>
<li>b. 分配器通过调用<code>OMX_GetParameter</code>来确定其管道端口的buffer需求。</li>
<li>c. 分配器端口根据自身和其管道端口对buffer需求的最大值来分配buffer。</li>
<li>d. 由于没有共享,没有buffer需要转递到共享端口。</li>
<li>e. 对每一块分配出来的buffer, 分配器端口调用其管道端口的<code>OMX_UseBuffer</code></li>
</ul>
</li>
</ol>
<p>所有共享组件的准则不适用与非共享组件。</p>
<p>###2.1.8 端口重连接<br>端口的重连接可以使一个管道组件被另一个管道组件替换而不需要卸载周围的组件。图2-10,组件B1被组件B2替换。要做到这一点,组件A的输出端口和组件B的输入端口首先应该用disable的命令禁用。一旦所有所有分配的buffer回到他们的拥有者并且释放,组件A的输出端口便可以连接到组件B2.组件B1输出端口和组件C的输入端口应该给予同样的禁用命令。所有分配buffer回到他们的拥有者并被释放后,组件C的输入端口可以重新连接到组件B2的输出端口。然后,可以给所有的端口发启用命令。</p>
<p><img src="img/2_10.png" alt=""></p>
<p><strong>图 2-10. 端口重连接</strong></p>
<p>在某些情况下,例如音频,将一个组件重新连接到另一个组件,老的组件淡出新的组件淡入也是可以的。图2-11展示了这是如何工作的。步骤1,组件A发送数据给组件B1。步骤2,IL客户端首先建立组件A和B2之间的管道,再建立B2和C之间的管道,然后启用两个管道上的所有端口。组件C可能将B1和B2通过不同的增益进行混音。步骤3,组件B1和组件A,C连接的端口都被禁用,B1的资源也会被释放。</p>
<p><img src="img/2_11.png" alt=""></p>
<p><strong>图 2-11. 组件重连接</strong></p>
<p>###2.1.9 队列和清空<br>一个单独的命令队列能够在使用非管道通信时让组件将没有处理的buffer清空并返回给IL客户端,或在使用管道通信是返回给管道端口。图2-12,假设端口有一个输出端口,它使用了IL客户端分配的buffer。在这个例子中,客户端在发送清空命令之前发送了一串共5块buffer给组件。处理清空命令时,组件按照原先的顺序返回每一个未处理的buffer,并触发事件处理程序通知IL客户端。有两块buffer已经在收到清空命令之前被处理了。组件返回剩下的三块buffer并产生一个事件。IL客户端应该等待此时间然后再去尝试释放这个组件。</p>
<p><img src="img/2_12.png" alt=""></p>
<p><strong>图 2-12. 清空队列</strong></p>
<p>###2.1.10 标记buffer<br>当遇到标记buffer是,IL客户端还可以触发一个事件。一块buffer可以在其头部被标记。标记在OpenMAX组件的输入端口和输出端口直接内部传递。当遇到这块标记buffer是,组件可以发送一个时间给IL客户端。图2-13显示了这是怎么工作的。</p>
<p><img src="img/2_13.png" alt=""></p>
<p><strong>图 2-13. 标记buffer</strong><br>IL客户端发送一个命令来标记buffer。组件的输出端口发送的下一个buffer被标记成B1。组件B处理buffer B1后提供了加入此标记的buffer B2.当组件C从输入端口中收到这个标记过的buffer B2,组件处理这块buffer出发事件处理程序。</p>
<p>###2.1.11 时间和回调<br>组件发送给客户端一共有六种事件:</p>
<ul>
<li>任何时间都可能遇到错误时间</li>
<li>命令成功处理后会触发一个命令完成通知时间</li>
<li>组件检测到一块标记的buffer时会触发标记buffer事件</li>
<li>当组件改变其端口设置时会触发端口设置改变通知事件</li>
<li>码流结束时(EOS)会触发buffer标志事件。</li>
<li>组件获得正在等待的资源时会触发资源获得事件。</li>
</ul>
<p>端口标记buffer的处理回调指示了buffer的可用性或表明buffer是需要的。</p>
<p>###2.1.12 Buffer载荷(Payload)<br>端口的配置用于确定传输到组件端口上的数据格式,但配置并没有定义数据怎么样存储在buffer中的。</p>
<p>通常有三种情况描述了数据如何填充buffer,每一种都有其优点。</p>
<p>在所有的情况下,buffer中有效的数据范围和位置通过buffer头部中的参数<code>pBuffer</code>, <code>nOffset</code> 和<code>nFilledLength</code>来定义。参数<code>pBuffer</code>指向了buffer的起始地址。参数<code>nOffset</code>指示了buffer的起始位置和有效数据开始之间的字节数。参数<code>nFilledLength</code>指定了buffer中连续有效数据的字节数。因此buffer中的有效数据位于<code>pBuffer</code> + <code>nOffset</code> 和 <code>pBuffer</code> + <code>nOffset</code> + <code>nFilledLength</code>之间。</p>
<p>下面的案例代表了在编解码时输入或输出到一个组件的压缩过的数据。在所有的情况中,buffer仅为数据提供传输机制,而对内容没有特别的要求。对内容的要求有端口配置参数定义。</p>
<p>buffer的阴影部分表示数据,白色部分表示没有数据。</p>
<p>情况1:每块buffer全部或部分填充。在含有压缩数据帧的时候,帧由f1到fn表示。</p>
<p><img src="img/2_13_1.png" alt=""></p>
<p>情况1的优点在于解码回放的时候。buffer可以容纳多个帧以减少解码时候的所需的buffer数量。但这种情况下,解码器需要在解码帧的时候解析数据。它也要求解码器组件有一个帧生成buffer,用于放置被解析的数据或维护下一个buffer才能来的完成的部分帧。</p>
<p>情况2:每一块buffer都被完整的压缩数据帧填充。</p>
<p><img src="img/2_13_2.png" alt=""></p>
<p>情况2不同与情况1,它需要压缩的数据首先被解析一遍以保证只有完整的帧被放在buffer中。案例2 也需要解码组件解析数据,但可能不需要额外的工作buffer用于解析帧。</p>
<p>情况3:每一块buffer仅被一个压缩数据帧填充。</p>
<p><img src="img/2_13_3.png" alt=""></p>
<p>案例3的好处是解码组件并不需要解析数据。解析的工作在源组件中完成。但对于这种方式,数据传输是瓶颈。数据传输一次只能传递一帧。基于这种时间,每一帧传输的消耗可能比从buffer中解析帧有更大的消耗。</p>
<p>一个编码器或解码器至少要支持第一种情况。根据定义,编解码其可以支持情况1,那么他可以支持情况2和3,但只有但压缩格式允许帧边界的字节对其。情况2或3的可能没有意义,例如,在RTP-payload格式,bandwidth-efficient模式的AMR的配置中。这种格式定义并不是字节对其,并不适合这些情况定义的字节对齐的帧边界。</p>
<p>当为解码器的输入或者编码器的输出用压缩数据填充一块buffer的时候,只有当帧不是字节对齐时才会遇到限制填充完整帧的问题。在格式的协议之外必须加入额外的填充。之后填充会被删除,因为数据无法被附加。这需要拥有标准规范以外的填充位的知识。同样,如果填充不到位,无法保证标准符合端口配置的标准规范,完整的帧无法被放入buffer中。在这两种情况下,必须知道如果处理这种情况,而且每个组件是不同的。</p>
<p>为了保证通用性,buffer中存储的内容不能假设或要求是完整的若干帧,但对未压缩的数据格式,至少有一个完整数据单元会存在与一个buffer中。压缩数据格式不限制每个buffer中传递的内容量。</p>
<p>###2.1.13 Buffer标记和时间戳<br>buffer标记与buffer包含的数据的某些属性关联。buffer的时间戳以微秒为单位,表示数据被显示的时间。一旦一个时间戳和一块buffer关联,没有组件应该修改这个用于速率控制或同步的时间戳。同步是在时钟组件中实现的。</p>
<p>buffer元数据(即标记和时间戳)适用于buffer中的第一个逻辑单元。因此,buffer中存在多个逻辑单元是,元数据适用于起始边界在buffer中的逻辑单元。除非另有规定(例如,一个标记的定义),一个组件收到有标记或者时间戳的逻辑单元应该将这个元数据拷贝到输入产生的逻辑输出单元中。</p>
<p>###2.1.14 同步<br>同步是靠启用时钟组件上的同步端口来实现的。这些端口和时钟组件被定义在其他(other)域,但操作协议和方法和数据端口一致。时钟组件维护了一个媒体时钟,基于音视频参考时钟,用于跟踪媒体流中的位置。时钟组件通过同步端口发送包含时间信息buffer到客户端组件(由媒体时间更新,包含了媒体时钟的当前位置,缩放和状态)。客户端组件可以通过要求时钟组件发送时间戳来给一个操作确定执行的时间(例如,视频帧的显示)。在这个例子中,客户端组件当收到请求执行时执行操作。图2-14展示了时间和数据buffer流程的一个例子。</p>
<p><img src="img/2_14.png" alt=""></p>
<p><strong>图 2-14. 时间和数据buffer的流程</strong></p>
<p>###2.1.15 速率控制<br>时钟组件还通过暴露一组控制媒体时钟的配置实现了所有的速率控制。IL客户端可能会改变媒体时钟的缩放因子来实现播放,快进,快退,暂停和慢动作特技。IL客户端可以通过改变媒体时钟的状态开始或停止时钟。时钟组件通过向所有的同步端口发送新的缩放或状态的媒体时间更新消息来改变使他所有的客户端组件知道媒体时钟缩放和状态的变化。虽然组件无法改变buffer的时间戳来响应缩放,但他可以响应的改变他的处理流程。例如,音频组件可以在特技播放时调整音调或完全停止输出。</p>
<p>###2.1.16 组件注册<br>通常组件是如何注册到核心是核心自己来定义的。</p>
<p>然而,如果核心支持与组件的静态连接,那么他将支持一个标准的在编译时的组件注册机制,如第3节所述。因此,供应商可以提供组件所有核心支持的合适静态连接的组件,这是通过将组件信息放入数据结构中,这是核心和组件的联系。</p>
<p>一个组件可以使用这个机制静态注册,但他的大部分代码是动态加载的。</p>
<p>###2.1.17 资源管理器<br>这一小节讨论OpenMAX IL API中的资源管理器的角色。</p>
<p>####2.1.17.1 资源管理的需求<br>当组件由于资源不足而不发进入idle状态时,IL客户端不知道缺乏那些资源或是那些组件正在使用这个组员。因此,IL客户端无法关掉所有的组件强制释放音频流(例如),除非知道IL组件是怎么具体实现的。这两种情况都不是可行的选择。这些情况需要IL的资源管理。</p>
<p>OpenMAX的一个目的是提供给上层一个硬件无关的软件层。硬件无关的目标可以通过实现指定资源管理的下列要求来实现:</p>
<ul>
<li>IL客户端(例如,通常是一个软件系统的多媒体插件)不需要知道IL实现的细节或组件使用的资源。例如,IL客户端可能不知道组件是否是硬件加速的。</li>
<li>在资源冲突的情况下,IL客户端可以信赖组件在不同硬件平台上的实现是同一的行为。</li>
<li>一个IL客户端不应该和硬件供应商的资源管理器直接连接,有下面两个原因。<ul>
<li>这种方法违背了硬件无关性的目标。</li>
<li>这种方法增加了IL客户端相当大的工作,因为影响了IL客户端在多个硬件平台上的可复用性。</li>
</ul>
</li>
</ul>
<p>虽然资源管理没有在OpenMAX IL API的1.0版本中彻底解决,“钩子(hook)”资源管理器已经放在了相应的位置包括行为的准则,组件的优先级,资源管理相关的组建状态。这些“钩子”作为后续版本OpenMAX IL API的基础。</p>
<p>在进一步讨论之前,资源管理和策略的术语有必要阐述一下:</p>
<ul>
<li>资源管理负责管理组件对有限资源的访问。资源管理器将知道有多少特定的资源可用,那些组件使用当前资源,以及组件使用的资源有多少。资源管理器将推荐策略,组件可以根据资源可用性和冲突抢占或继续。</li>
<li>策略负责管理组件链或流。策略管理器根据资源管理、系统配置、应用程序请求或其他因素来确定是否允许运行或继续</li>
</ul>
<p>####2.1.17.2 架构假设<br>下面的讨论提出了两个关于OpenMAX IL的架构假设:</p>
<ul>
<li>假设1:一个框架包含客户端和OpenMAX IL之间的策略管理器</li>
<li>假设2:一个系统可以有一个或多个硬件平台,有不同的OpenMAX组件,并被硬件特定的资源管理器管理</li>
</ul>
<p>这些假设如上层架构图图2-15所示。如果一个系统没有架构(即,用户程序接口直接与IL连接),OpenMAX IL API协议没有规定资源管理是如何进行的。假设2规定系统有一个同一集中的资源管理器。</p>
<p><img src="img/2_15.png" alt=""></p>
<p><strong>Figure 2-15. 架构假设</strong></p>
<p>为保证资源冲突是组件的行为是一直的,组件优先级和行为准则的基本定义是必要的。</p>
<p>####2.1.17.3 组件优先级</p>
<p>每一个IL组件有一个优先级值(一个OMX_32整型数),由IL客户端设置。优先级的实际范围可以留给平台,但优先级的顺序是重要的,并且在IL的实现中要一致:递减的优先级顺序。即0是最高优先级。下面的准则也适用:当相同优先级组件进行比较时,最近获得资源的组件应该有更高的优先级。</p>
<p>####2.1.17.4 行为准则<br>IL层定义了下面的行为准则:</p>
<ul>
<li>错误<code>OMX_ErrorInsufficientResources</code>仅当组件试图进入idle状态但没有足够资源或是资源无法被低优先级的组件释放时调用。</li>
<li>组件不知道当他试图进入idle状态时会发生资源抢占,资源需要被低优先级的组件释放。</li>
<li>当一个组件已经被抢占,当从Executing或pause状态转移到idle时,发出<code>OMX_ErrorResourcesPreempted</code>错误,如果从idle转移到loaded状态时,发出 <code>OMX_ErrorResourcesLost</code> 错误给IL客户端,</li>
<li>如果IL客户端想知道什么时候和流相关的组件可以被启动或继续,IL客户端则应该要求当资源可用时被通知。这是通过将组件转移到<code>OMX_StateWaitForResources</code>状态。当资源可用时,组件自动进入idle状态。当客户端收到组件进入idle状态的通知是,它会尝试将其他的链上的组件也转移到idle状态。这种向idle状态的资源的自动转移可以确保当多个IL客户端等待同一个资源时,IL客户端可以当资源可用时立即开始或恢复。如果组件自动转移到loaded状态,其他的IL客户端可以首先获得资源。这些行为准则可以覆盖IL客户端和组件之间的交互。</li>
</ul>
<p>####2.1.17.5 硬件厂商资源管理器<br>要实现行为准则,需要在IL层下拥有一个硬件厂商的资源管理器,并执行下面的功能:</p>
<ul>
<li>实现并管理等待队列。</li>
<li>跟踪可用资源。</li>
<li>跟踪每一个拥有资源的组件和被使用的资源。</li>
<li>当一个高优先级组件请求资源时,通知一个或多个组件让他们放弃他们的资源。</li>
<li>当资源可用时通知等待资源高优先级的组件。</li>
</ul>
<p>组件和硬件资源管理器之间的实际交互是基于特定厂商并超出了本文档的范围。第三节提供了优先级和资源管理相关参数结构和用例的更多细节。</p>
]]></content>
<summary type="html">
<p>#OpenMAX IL 介绍和框架<br>本章介绍了OpenMAX的特点和框架</p>
<p>##2.1 OpenMAX IL 简介<br>OpenMAX IL层API定义了一个用于在系统提供的软件组件的接入层软件接口。目的是让拥有不同方法的组件提供一个标准化的接口和命令
</summary>
</entry>
<entry>
<title>OpenMax标准协议 第三章 OpenMAX IL控制API</title>
<link href="http://yoursite.com/2017/04/01/chapter3/"/>
<id>http://yoursite.com/2017/04/01/chapter3/</id>
<published>2017-04-01T03:20:10.000Z</published>
<updated>2017-04-06T03:28:50.667Z</updated>
<content type="html"><![CDATA[<p>#3 OpenMAX IL控制API<br>OpenMAX IL API允许IL客户端控制音频、视频、图像领域上的组件。“其他”领域还包括额外的一些功能,例如音视频同步。OpenMAX IL API的使用者往往是一个多媒体框架。在本文档的其他部分,OpenMAX IL API的使用者指的就是IL客户端。</p>
<p>OpenMAX IL API定义了一组头文件,他们的名称是:</p>
<ul>
<li><code>OMX_Types.h</code>: OpenMAX IL使用的数据类型</li>
<li><code>OMX_Core.h</code>: OpenMAX IL 核心 API</li>
<li><code>OMX_Component.h</code>: OpenMAX 组件 API</li>
<li><code>OMX_Audio.h</code>: OpenMAX 音频数据结构</li>
<li><code>OMX_IVCommon.h</code>: OpenMAX 视频和图像通用的数据结构</li>
<li><code>OMX_Video.h</code>: OpenMAX 视频数据结构</li>
<li><code>OMX_Image.h</code>: OpenMAX 图像据结构</li>
<li><code>OMX_Other.h</code>: OpenMAX 其他的数据结构 (包括音视频同步)</li>
<li><code>OMX_Index.h</code>: OpenMAX定义的数据结构的索引</li>
</ul>
<p>本节介绍了如果配置OpenMAX Core和OpenMAX组件的操作。</p>
<p>首先介绍了OpenMAX的数据类型。其次,阐述了OpenMAX Core的方法。组件的实现的方法在第3.3节中讨论。最后,第3.4节介绍了一些操作的调用顺序,包括组件的初始化,普通数据流,数据管道的建立,数据管道中数据流。这些时序图介绍了IL客户端,IL Core和OpenMAX组件之间的交互。</p>
<p>下面约定用于记录接口方法参数:</p>
<ul>
<li><参数名> [输入] 指定一个输入参数,由函数调用者设置并被函数读取。</li>
<li><参数名> [输出] 指定一个输出参数,由函数本身设置并返回给调用者。当函数返回时,调用者读取通过引用传递的参数的新值。</li>
<li><参数名> [输入输出] 指定一个输入/输出参数,由函数调用者设置。函数改变这个参数的值并返回给调用者。</li>
</ul>
<p>参数的分类可以在OpenMAX的头文件中找到,里面定义了空的宏: <code>OMX_IN</code>, <code>OMX_OUT</code> 和 <code>OMX_INOUT</code>。<code>OMX_IN</code>对应 <参数名> [输入], <code>OMX_OUT</code>对应<参数名> [输出], <code>OMX_INOUT</code> 对应<参数名> [输入输出]</p>
<p>##3.1 OpenMAX 类型</p>
<p>###3.1.1 枚举<br><code>OMX_Core.h</code>中定义了5个32位整型枚举数</p>
<ul>
<li><code>OMX_ERRORTYPE</code> 为每一个OpenMAX IL API方法的返回值(见3.1.1.3小节)</li>
<li><code>OMX_COMMANDTYPE</code> 包含了所有IL客户端发往组件的命令(见小节3.1.1.1)</li>
<li><code>OMX_EVENTTYPE</code> 包括了OpenMAX组件产生并传递给IL客户端的消息(见3.1.1.4节)。</li>
<li><code>OMX_BUFFERSUPPLIERTYPE</code> 包括了管道端口中所有可能的buffer供应者。3.1.1.5小节可以看到这个枚举类型用法的描述。</li>
<li><code>OMX_STATETYPE</code>, 在3.1.1.2中描述。</li>
</ul>
<p>图 3-1 显示了<code>OMX_Core.h</code>定义的枚举类型</p>
<p><img src="img/3_1.png" alt=""></p>
<p><strong>图 3-1. OMX_Core.h中定义的枚举类型</strong></p>
<p>####3.1.1.1 OMX_COMMANDTYPE<br>表3-1展示了IL客户端可以向OpenMAX组件发送的消息类型。由于消息是非阻塞的,当消息处理完毕后, OpenMAX组件会生成一个消息完成回调。<br>回调是在一个专门的结构中定义,见3.1.2.7小节。</p>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>OMX_CommandStateSet</td>
<td>切换组件状态</td>
</tr>
<tr>
<td>OMX_CommandFlush</td>
<td>清空组件上一个端口的buffer队列</td>
</tr>
<tr>
<td>OMX_CommandPortDisable</td>
<td>禁用组件上一个端口</td>
</tr>
<tr>
<td>OMX_CommandPortEnable</td>
<td>启用组件上一个端口</td>
</tr>
<tr>
<td>OMX_CommandMarkBuffer</td>
<td>标记一块buffer并指定接受标记时间的组件</td>
</tr>
</tbody>
</table>
<p>表 3-2 描述了每一个命令需要的参数。</p>
<table>
<thead>
<tr>
<th>命令代码</th>
<th>参数</th>
<th>数据</th>
</tr>
</thead>
<tbody>
<tr>
<td>OMX_CommandStateSet</td>
<td>OMX_STATETYPE – 要转移的状态</td>
<td>无</td>
</tr>
<tr>
<td>OMX_CommandFlush</td>
<td>OMX_U32 – 目标端口ID</td>
<td>无</td>
</tr>
<tr>
<td>OMX_CommandPortDisable</td>
<td>OMX_U32 – 目标端口ID</td>
<td>无</td>
</tr>
<tr>
<td>OMX_CommandPortEnable</td>
<td>OMX_U32 – 目标端口ID</td>
<td>无</td>
</tr>
<tr>
<td>OMX_CommandMarkBuffer</td>
<td>OMX_U32 – 目标端口ID</td>
<td>OMX_MARKTYPE* - 标记数据和目标组件</td>
</tr>
</tbody>
</table>
<p><strong>表 3-2. 命令语法</strong></p>
<p>####3.1.1.2 OMX_STATETYPE<br>表3-2展示了IL客户端调用了一系列<code>OMX_SendCommand</code>(<code>OMX_StateSet</code>, <状态>)后的状态转移,新的状态当参数传递给组件。尖括号包围的转移名表示转换不是由IL客户端命令触发的,而是由一系列组件内部事件的结果。</p>
<p><img src="img/3_2.png" alt=""></p>
<p><strong>图 3-2. OpenMAX 组件状态转移</strong></p>
<p>这个小节描述了组件的状态。IL客户端通过调用<code>OMX_SendCommand</code>发送<code>OMX_CommandStateSet</code>命令来切换组件状态。</p>
<p>表 3-3 展示了OpenMAX组件的状态</p>
<table>
<thead>
<tr>
<th>字段名</th>
<th>描述</th>
<th>是否获取资源</th>
<th>buffer位置</th>
</tr>
</thead>
<tbody>
<tr>
<td>OMX_StateInvalid</td>
<td>组件已损坏或遇到无法回复的错误</td>
<td>未知</td>
<td>未知</td>
</tr>
<tr>
<td>OMX_StateLoaded</td>
<td>组件已加载但没有获得资源</td>
<td>否</td>
<td>无</td>
</tr>
<tr>
<td>OMX_StateIdle</td>
<td>组件已获得资源但没有转递任何buffer或开始处理数据</td>
<td>是</td>
<td>只有供应者</td>
</tr>
<tr>
<td>OMX_StateExecuting</td>
<td>组件以开始转递buffer并处理数据</td>
<td>是</td>
<td>供应者和非供应者</td>
</tr>
<tr>
<td>OMX_StatePause</td>
<td>组件暂停处理数据但可能会从暂停点恢复</td>
<td>是</td>
<td>供应者和非供应者</td>
</tr>
<tr>
<td>OMX_StateWaitForResources</td>
<td>组件在等待可用资源</td>
<td>否</td>
<td>无</td>
</tr>
</tbody>
</table>
<p><strong>表 3-3. OpenMAX 组件状态</strong></p>
<p>######3.1.1.2.1 OMX_StateLoaded<br>在调用<code>OMX_GetHandle</code>创建组件之后,分配资源之前,组件处于<code>OMX_StateLoaded</code>状态。在这个状态,IL客户端可以通过<code>OMX_SetParameter</code>改变组件参数,创建组件端口上的数据通道,或者切换组件状态至<code>OMX_StateIdle</code>或<code>OMX_StateWaitForResources</code>。</p>
<p>IL客户端可以选择一个处于<code>OMX_StateLoaded</code>的组件转移到<code>OMX_StateWaitForResources</code>状态,例如,组件未能获得切换到<code>OMX_StateIdle</code>状态的资源。</p>
<h6 id="3-1-1-2-1-1-OMX-StateLoaded-到-OMX-StateIdle"><a href="#3-1-1-2-1-1-OMX-StateLoaded-到-OMX-StateIdle" class="headerlink" title="3.1.1.2.1.1 OMX_StateLoaded 到 OMX_StateIdle"></a>3.1.1.2.1.1 OMX_StateLoaded 到 OMX_StateIdle</h6><p>如果IL客户端请求状态由<code>OMX_StateLoaded</code>切换到<code>OMX_StateIdle</code>,组件必须在完成状态切换前获得所有的资源,包换buffer。此外,在状态切换完成之前,buffer的提供者(在非管道模式时为IL客户端),必须保证非提供者拥有他所有的buffer。如果一个端口连接到IL客户端,IL客户端可以自己分配buffer并通过调用端口上的<code>OMX_UseBuffer</code>方法转递给端口,或者调用端口上<code>OMX_AllocateBuffer</code>命令让端口直接分配。</p>
<p>当端口出于管道状态,供应端口要么自己分配buffer,要么当端口实现了buffer共享时,复用同组件上的其他端口上的buffer。管道供应端口则通过调用非供应者的<code>OMX_UseBuffer</code> 将buffer转递给非供应者。</p>
<p>端口上的buffer数量由端口的定义(见<code>OMX_IndexParamPortDefinition</code>)确定,默认是最小值(见同一个数据结构)。但在提供者可以调用<code>OMX_UseBuffer</code> 和<code>OMX_AllocateBuffer</code>之前可以通过调用 <code>OMX_SetParameter</code>修改此值。</p>
<p>#####3.1.1.2.2 OMX_StateIdle<br>在<code>OMX_StateIdle</code>状态时,组件已经可以被使用,这意味着所有必要的资源已经分配。但是,提供者仍然保留着buffer,并没有发生buffer交换或处理。因此,如果这个状态由<code>OMX_StateExecuting</code>或<code>OMX_StatePause</code>转移而来,组件必须归还他正在处理的所有buffer给他的提供者。IL客户端可能会转移到除了<code>OMX_StateInvalid</code>和<code>OMX_StateWaitForResources</code>任何其他状态。</p>
<p>######3.1.1.2.2.1 OMX_StateIdle 到 OMX_StateLoaded<br>在从<code>OMX_StateIdle</code> 到 <code>OMX_StateLoaded</code>的转移过程中,每一个buffer提供者必须为非提供者端口上的每一块buffer调用<code>OMX_FreeBuffer</code>方法。如果提供者分配了buffer,他必须在调用<code>OMX_FreeBuffer</code>之前释放buffer。如果非供应端口分配了buffer,他必须收到<code>OMX_FreeBuffer</code>调用时释放内存。此外,非供应端口总是必须收到<code>OMX_FreeBuffer</code>调用时释放buffer头。当所有的buffer被移出组件时,状态转移完成。组件通过一个回调时间表示调用<code>OMX_SendCommand</code>完成。</p>
<p>######3.1.1.2.2.2 OMX_StateIdle 到 OMX_StateExecuting<br>如果IL客户端请求将状态由<code>OMX_StateIdle</code>切换至<code>OMX_StateExecuting</code>,组件应该开始转移并处理数据。和IL客户端通信的端口,IL客户端会通过<code>OMX_EmptyThisBuffer</code>和<code>OMX_FillThisBuffer</code>初始化数据传输。在管道端口中,任何输入端口也是供应端口,应该把它的空buffer通过调用<code>OMX_FillThisBuffer</code>转移给他的管道输出端口。</p>
<p>#####3.1.1.2.3 OMX_StateExecuting<br>在这个状态中,OpenMAX组件传输并处理数据。组件应该接受其输入端口的<code>OMX_EmptyThisBuffer</code> 调用和输出端口的<code>OMX_EmptyThisBuffer</code>。任何与IL端口通信的端口应该调用回调函数<code>EmptyBufferDone</code>和<code>FillBufferDone</code>返回空或满的buffer给IL客户端。管道端口应该调用<code>OMX_FillThisBuffer</code>或<code>OMX_EmptyThisBuffer</code>返回空或满的buffer给管道端口的另一段。IL客户端可以将组件从<code>OMX_StateIdle</code>或<code>OMX_StatePaused</code>转移至<code>OMX_StateExecuting</code>。</p>
<p>######3.1.1.2.3.1 OMX_StateExecuting 到 OMX_StateIdle<br>如果IL客户端请求状态由<code>OMX_StateExecuting</code>转移到<code>OMX_StateIdle</code>,组件应该在转移完成之前归换所有的buffer给他的提供者,并且接受所有自身提供者端口上的buffer。任何与IL客户端通信的端口应该通过<code>OMX_EmptyBufferDone</code>和<code>OMX_FillBufferDone</code>返回自己持有的buffer,这些buffer本来是分别给输入或输出端口使用的。任何管道端口应该通过<code>OMX_EmptyBufferDone</code>和<code>OMX_FillBufferDone</code>返回自己持有的buffer给管道另一端的端口。同理,非供应管道端口应该等待他的管道端口返回所有的buffer。</p>
<p>#####3.1.1.2.4 OMX_StatePause<br>在这个状态下,OpenMAX组件不传输或者处理数据,但buffer也不会返回给供应者。<code>OMX_StatePause</code>转移到<code>OMX_StateExecuting</code>,执行可以继续并且可能不会丢失数据。组件在自己的输入端口上可能继续接受数据,但这些buffer仅仅存放到队列中但不会进一步处理。 IL客户端可能将组将由<code>OMX_StatePause</code>转移至<code>OMX_StateIdle</code>或<code>OMX_StateExecuting</code>。在<code>OMX_StatePause</code>向<code>OMX_StateIdle</code>转移时,组件应该想他的供应者归还所有的buffer,方式描述参见3.1.1.2.3.1小节。</p>
<p>#####3.1.1.2.5 OMX_StateWaitForResources<br>在这个状态中,组件等待一个或多个需要的资源。这个状态和资源管理器有关。假设系统有一个或多个硬件特有的资源管理器来管理资源。OpenMAX组件和资源管理器之间的交互不再本标准讨论范围内。</p>
<p>如果处于<code>OMX_StateLoaded</code>状态的组件由于非buffer资源不足而无法切换至<code>OMX_StateIdle</code>状态是,IL客户端如果希望知道什么时候资源变得可用,那么可以将组件至于<code>OMX_StateWaitForResources</code>状态。IL客户端可以通过由<code>OMX_StateWaitForResources</code>状态转移至 <code>OMX_StateLoaded</code>命令组件停止等待资源。如果在<code>OMX_StateWaitForResources</code>状态的组件得到了所有等待的资源,它应该开始转移至<code>OMX_StateIdle</code>。</p>
<p>######3.1.1.2.5.1 OMX_StateWaitForResources 到 OMX_StateIdle<br>当组件开始从<code>OMX_StateWaitForResources</code>向<code>OMX_StateIdle</code>转移,它应该通过事件<code>OMX_EventResourcesAcquired</code>向IL客户端进行通知。当IL客户端收到<code>OMX_EventResourcesAcquired</code>时间,它应该调用<code>OMX_UseBuffer</code> 和<code>OMX_AllocateBuffer</code>,和从<code>OMX_StateLoaded</code>向 <code>OMX_StateIdle</code>一样,同理,除非组件获得了所有的资源,包括buffer,他不能完成到<code>OMX_StateIdle</code>的状态转移。</p>
<p>#####3.1.1.2.6 OMX_StateInvalid<br>在这个状态时,组件发现内部损坏或遇到无法恢复的错误。当它检测到这个情况是,组件将自己转移到<code>OMX_StateInvalid</code>并通知IL客户端产生一个值为<code>OMX_ErrorInvalidState</code>的<code>OMX_ErrorEvent</code>事件。 但客户端收到这个时间。它应该释放组件关联的所有资源并且最后调用<code>OMX_FreeHandle</code>释放组件关联的句柄。</p>
<p>位于<code>OMX_StateInvalid</code>状态的组件应该除了 <code>OMX_GetState</code>, <code>OMX_FreeBuffer</code>, 或<code>OMX_ComponentDeinit</code>方法调用外,其他的调用都失败并返回<code>OMX_ErrorStateInvalid</code>错误信息。IL组件应该同样明确的通过<code>OMX_SendCommand</code>将组件转移到<code>OMX_StateInvalid</code>状态。组件可以从任意状态转移到<code>OMX_StateInvalid</code>。</p>
<p>####3.1.1.3 OMX_ERRORTYPE<br>表3-4描述了枚举类型<code>OMX_ERRORTYPE</code>,它定义了每一个OpenMAX IL API返回的OpenMAX的标准错误。这些错误可以覆盖大多数的普通错误。但是硬件厂商可以根据下面的原则自由的加入额外的错误类型:</p>
<ul>
<li>厂商的错误消息范围是0x90000000到0x9000FFFF。</li>
<li>厂商错误消息应该定义在和组件一起提供的头文件中。未定义的错误消息是不允许的。</li>
</ul>
<table>
<thead>
<tr>
<th>字段名称</th>
<th style="text-align:center">值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>OMX_ErrorNone</td>
<td style="text-align:center">0</td>
<td>函数返回正确</td>
</tr>
<tr>
<td>OMX_ErrorInsufficientResources</td>
<td style="text-align:center">0x80001000</td>
<td>执行请求操作没有足够的资源</td>
</tr>
<tr>
<td>OMX_ErrorUndefined</td>
<td style="text-align:center">0x80001001</td>
<td>未知原因的错误</td>
</tr>
<tr>
<td>OMX_ErrorInvalidComponentName</td>
<td style="text-align:center">0x80001002</td>
<td>组件名错误</td>
</tr>
<tr>
<td>OMX_ErrorComponentNotFound</td>
<td style="text-align:center">0x80001003</td>
<td>没有找到指定名称的组件</td>
</tr>
<tr>
<td>OMX_ErrorInvalidComponent</td>
<td style="text-align:center">0x80001004</td>
<td>指定组件没有<code>OMX_ComponentInit</code>入口,或者组件没有完成<code>OMX_ComponentInit</code>调用</td>
</tr>
<tr>
<td>OMX_ErrorBadParameter</td>
<td style="text-align:center">0x80001005</td>
<td>一个或多个参数非法</td>
</tr>
<tr>
<td>OMX_ErrorNotImplemented</td>
<td style="text-align:center">0x80001006</td>
<td>请求功能未实现</td>
</tr>
<tr>
<td>OMX_ErrorUnderflow</td>
<td style="text-align:center">0x80001007</td>
<td>下一个buffer准备好之前目前的buffer已空</td>
</tr>
<tr>
<td>OMX_ErrorOverflow</td>
<td style="text-align:center">0x80001008</td>
<td>需要buffer的时候不可用</td>
</tr>
<tr>
<td>OMX_ErrorHardware</td>
<td style="text-align:center">0x80001009</td>
<td>硬件响应错误</td>
</tr>
<tr>
<td>OMX_ErrorInvalidState</td>
<td style="text-align:center">0x8000100A</td>
<td>组件处于<code>OMX_StateInvalid</code>状态</td>
</tr>
<tr>
<td>OMX_ErrorStreamCorrupt</td>
<td style="text-align:center">0x8000100B</td>
<td>发现流损坏</td>
</tr>
<tr>
<td>OMX_ErrorPortsNotCompatible</td>
<td style="text-align:center">0x8000100C</td>
<td>建立管道的端口不兼容</td>
</tr>
<tr>
<td>OMX_ErrorResourcesLost</td>
<td style="text-align:center">0x8000100D</td>
<td>处于<code>OMX_StateIdle</code> 状态的组件丢失了分配的资源, 导致组件回到<code>OMX_StateLoaded</code>状态</td>
</tr>
<tr>
<td>OMX_ErrorNoMore</td>
<td style="text-align:center">0x8000100E</td>
<td>没有更多的索引可以枚举。</td>
</tr>
<tr>
<td>OMX_ErrorVersionMismatch</td>
<td style="text-align:center">0x8000100F</td>
<td>组件检测到版本不匹配。</td>
</tr>
<tr>
<td>OMX_ErrorNotReady</td>
<td style="text-align:center">0x80001010</td>
<td>组件此时没有准备好返回数据。</td>
</tr>
<tr>
<td>OMX_ErrorTimeout</td>
<td style="text-align:center">0x80001011</td>
<td>发生超时.</td>
</tr>
<tr>
<td>OMX_ErrorSameState</td>
<td style="text-align:center">0x80001012</td>
<td>组件试图切换至当前正处于的状态</td>
</tr>
<tr>
<td>OMX_ErrorResourcesPreempted</td>
<td style="text-align:center">0x80001013</td>
<td>处于 <code>OMX_StateExecuting</code>或 <code>OMX_Pause</code>状态的组件所分配的资源被抢占,导致组件回到<code>OMX_StateIdle</code>状态</td>
</tr>
<tr>
<td>OMX_ErrorPortUnresponsiveDuringAllocation</td>
<td style="text-align:center">0x80001014</td>
<td>非供应端口认为等待供应端口调用<code>OMX_UseBuffer</code>来分配buffer时间过长。非供应端口在loaded向idle进行状态切换时或启用某一端口时通过<code>EventHandler</code>回调发送此错误给IL客户端</td>
</tr>
<tr>
<td>OMX_ErrorPortUnresponsiveDuringDeallocation</td>
<td style="text-align:center">0x80001015</td>
<td>非供应端口认为等待供应端口调用<code>OMX_FreeBuffer</code>来释放buffer时间过长。非供应端口在idle向loaded进行状态切换时或禁用某一端口时通过<code>EventHandler</code>回调发送此错误给IL客户端</td>
</tr>
<tr>
<td>OMX_ErrorPortUnresponsiveDuringStop</td>
<td style="text-align:center">0x80001016</td>
<td>供应端口认为等待非供应端口调用<code>EmptyThisBuffer</code>或<code>FillThisBuffer</code>返回时间过长。供应端口在idle向loaded进行状态切换时或禁用某一端口时通过<code>EventHandler</code>回调发送此错误给IL客户端</td>
</tr>
<tr>
<td>OMX_ErrorIncorrectStateTransition</td>
<td style="text-align:center">0x80001017</td>
<td>试图进行不允许的状态转移</td>
</tr>
<tr>
<td>OMX_ErrorIncorrectStateOperation</td>
<td style="text-align:center">0x80001018</td>
<td>试图调用的命令和方法在当前状态是不支持的</td>
</tr>
<tr>
<td>OMX_ErrorUnsupportedSetting</td>
<td style="text-align:center">0x80001019</td>
<td>一个或多个参数或配置结构不正确</td>
</tr>
<tr>
<td>OMX_ErrorUnsupportedIndex</td>
<td style="text-align:center">0x8000101A</td>
<td>给出的索引参数或配置不支持</td>
</tr>
<tr>
<td>OMX_ErrorBadPortIndex</td>
<td style="text-align:center">0x8000101B</td>
<td>给出得端口索引不正确</td>
</tr>
<tr>
<td>OMX_ErrorPortUnpopulated</td>
<td style="text-align:center">0x8000101C</td>
<td>端口丢失了一个或多个buffer</td>
</tr>
</tbody>
</table>
<p><strong>Table 3-4. OpenMAX 错误代码</strong></p>
<p>####3.1.1.4 OMX_EVENTTYPE<br>枚举类型<code>OMX_EVENTTYPE</code>如表3-5所示,它包括了OpenMAX组件产生的事件类型。3.1.2.7小节描述了OpenMAX组件产生事件并通过回调传送给IL客户端。与事件关联的参数也一并通过回调传递。</p>
<table>
<thead>
<tr>
<th>字段名</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>OMX_EventCmdComplete</td>
<td>组件完成命令执行。</td>
</tr>
<tr>
<td>OMX_EventError</td>
<td>组件检测到错误。</td>
</tr>
<tr>
<td>OMX_EventMark</td>
<td>一个标记的buffer到达目标组件,IL客户端收到此带有指向私有数据指针的事件。</td>
</tr>
<tr>
<td>OMX_EventPortSettingsChanged</td>
<td>组件改变了端口设置。例如,组件根据比特流的解析相应的改变了端口设置。</td>
</tr>
<tr>
<td>OMX_EventBufferFlag</td>
<td>组件检测到码流结束(EOS)时发送的事件。</td>
</tr>
<tr>
<td>OMX_EventResourcesAcquired</td>
<td>组件得到资源并将从<code>OMX_StateWaitForResources</code>切换到<code>OMX_StateIdle</code></td>
</tr>
</tbody>
</table>
<p><strong>表 3-5. OpenMAX 事件类型</strong></p>
<p>#####3.1.1.4.1 OMX_EventCmdComplete<br>组件完成命令执行后会立刻产生<code>OMX_EventCmdComplete</code>事件传递给IL客户端。如果是组件状态改变,新状态会作为事件的参数。组件转移到<code>OMX_StateInvalid</code>不会产生此事件。</p>
<p>#####3.1.1.4.2 OMX_EventError<br>组件检测到下面的情况的错误时会产生`OMX_EventError`事件,错误事件类型会放在事件参数中,并使用<code>OMX_ERRORTYPE</code>中定义的值。组件应该通过<code>OMX_EventError</code>发送下面的错误:</p>
<ul>
<li>组件转移到<code>OMX_StateInvalid</code>状态时会发送<code>OMX_ErrorInvalidState</code>错误。</li>
<li>组件由于资源不足时从<code>OMX_StateExecuting</code> 或 <code>OMX_StatePause</code> 切换到 <code>OMX_StateIdle</code>时会发送<code>OMX_ErrorResourcesPreempted</code>错误。</li>
<li>组件由于资源丢失而从<code>OMX_StateIdle</code> 切换到 <code>OMX_StateLoaded</code>时会发送<code>OMX_ErrorResourcesLost</code>错误。</li>
</ul>
<p>#####3.1.1.4.3 OMX_EventMark<br>组件受到一块标记过的buffer时会产生<code>OMX_EventMark</code>事件。组件收到buffer时,他应该比较自身指针和buffer中<code>pMarkTargetComponent</code>字段。如果指针相等,组件处理完buffer后应该立即发送一个包含<code>pMarkData</code>参数的标记事件。IL客户端可以使用使用此标记事件来计算组件链上的传输延时,或通知组件一个快特殊的buffer已经到达目的地。</p>
<p>#####3.1.1.4.4 OMX_EventPortSettingsChanged<br>组件改变端口设置时会立刻产生<code>OMX_EventPortSettingsChanged</code>事件。例如,视频解码器可能不知道输出视频的帧大小和帧率,因为这些参数在输入比特流中编码。一旦这些组件被解析了,组件改变输出组件上的配置结构并且传递<code>OMX_EventPortSettingsChanged</code>事件给IL客户端。</p>
<p>#####3.1.1.4.5 OMX_EventBufferFlag<br>当一个输出端口发出一个在字段<code>nFlags</code>带有<code>OMX_BUFFERFLAG_EOS</code>标识的buffer时,组件产生<code>OMX_EventBufferFlag</code>事件。事件处理程序中的<code>nData1</code>字段指示了输出端口的索引, <code>nData2</code>字段指示了包含码流结束(EOS)标志的不可变的`nFlags`字段。如果组件不再传递流(例如,组件时一个视频或视频sink),组件处理完带有<code>OMX_BUFFERFLAG_EOS</code>的buffer后,应该为此流发送一个<code>OMX_EventBufferFlag</code>事件。事件处理程序的<code>nData1</code>字段指定了接受buffer的输入端口,`nData2`字段指定了含有EOS标志的不可变的<code>nFlags</code>字段。</p>
<p>#####3.1.1.4.6 OMX_EventResourcesAcquired<br>组件处于<code>OMX_StateWaitForResources</code>状态时,资源管理器检测到所需资源可用时,组件产生<code>OMX_EventResourcesAcquired</code>事件。组件收到这个事件时,它便可以转移状态到<code>OMX_StateIdle</code>,并且会所有端口上的buffer分配。</p>
<p>####3.1.1.5 OMX_BUFFERSUPPLIERTYPE<br>表3-6中的枚举类型`OMX_BUFFERSUPPLIERTYPE`指明了管道端口中的供应端口。一个供应端口要么自己分配buffer,要么复用同一组件下的另一个端口的buffer。</p>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>OMX_BufferSupplyUnspecified</td>
<td>0x0</td>
<td>提供buffer的端口未指定,或没有优先的提供者。</td>
</tr>
<tr>
<td>OMX_BufferSupplyInput</td>
<td></td>
<td>输入端口提供buffer。</td>
</tr>
<tr>
<td>OMX_BufferSupplyOutput</td>
<td></td>
<td>输出端口提供buffer。</td>
</tr>
</tbody>
</table>
<p><strong>表 3-6. OpenMAX管道建立时Buffer提供类型</strong></p>
<p>###3.1.2 结构<br>本小节讨论了OpenMAX core中定义的数据结构。每个OpenMAX组件的钱两个字段指明了结构的大小和小节3.1.2.4中定义的版本号<code>OMX_VERSIONTYPE</code>。分配OpenMAX结构的实例负责填充着两个值。</p>
<p>####3.1.2.1 OMX_COMPONENTREGISTERTYPE<br>`OMX_COMPONENTREGISTERTYPE`结构用于组件静态链接到core中时。Core使用此结构加载和运行特定的组件初始化方法。</p>
<p><code>OMX_COMPONENTREGISTERTYPE</code>定义如下.</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> OMX_COMPONENTREGISTERTYPE</div><div class="line">{</div><div class="line"> <span class="keyword">const</span> <span class="keyword">char</span> * pName;</div><div class="line"> OMX_COMPONENTINITTYPE pInitialize;</div><div class="line">} OMX_COMPONENTREGISTERTYPE;</div></pre></td></tr></table></figure>
<p>####3.1.2.2 OMX_COMPONENTINITTYPE Type Definition<br><code>OMX_COMPONENTINITTYPE</code>类型定义了组件初始化入口的程序指针。定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">OMX_ERRORTYPE</span> <span class="params">(* OMX_COMPONENTINITTYPE)</span><span class="params">(OMX_IN OMX_HANDLETYPE hComponent)</span></span>;</div></pre></td></tr></table></figure>
<p>#####3.1.2.2.1 pName<br><code>pName</code>包含了组件的名称,最大不超过128个字节(包括‘\0’)</p>
<p>#####3.1.2.2.2 pInitialize<br><code>pInitialize</code>包括了组件初始化函数的指针。</p>
<p>####3.1.2.3 OMX_ComponentRegistered[]<br>任何静态链接组件的core应该在<code>OMX_COMPONENTREGISTERTYPE</code>字段中声明它所有注册的全局组件列表。</p>
<p>####3.1.2.4 OMX_VERSIONTYPE<br><code>OMX_VERSIONTYPE</code>类型指示了组件或结构的版本。每个结构使用<code>OMX_VERSIONTYPE</code>字段指定了结构的OpenMAX版本。对OpenMAX IL 1.0版本,协议版本时1.0.0.0。组件结构也包含了一个厂商特定的组件版本号的<code>OMX_VERSIONTYPE</code>字段。</p>
<p><code>OMX_VERSIONTYPE</code>定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">typedef</span> <span class="keyword">union</span> OMX_VERSIONTYPE</div><div class="line">{</div><div class="line"> <span class="keyword">struct</span></div><div class="line"> {</div><div class="line"> OMX_U8 nVersionMajor;</div><div class="line"> OMX_U8 nVersionMinor;</div><div class="line"> OMX_U8 nRevision;</div><div class="line"> OMX_U8 nStep;</div><div class="line"> } ;</div><div class="line"> OMX_U32 nVersion;</div><div class="line">} OMX_VERSIONTYPE;</div></pre></td></tr></table></figure>
<p>#####3.1.2.4.1 nVersionMajor<br><code>nVersionMajor</code> 标识主要版本号.</p>
<p>#####3.1.2.4.2 nVersionMinor<br><code>nVersionMinor</code> 标识次要版本号.</p>
<p>#####3.1.2.4.3 nRevision<br><code>nRevision</code> 标识修订号.</p>
<p>#####3.1.2.4.4 nStep<br><code>nStep</code> 步骤号。</p>
<p>####3.1.2.5 OMX_PRIORITYMGMTTYPE<br><code>OMX_PRIORITYMGMTTYPE</code>类型指示了组件组的被指定的优先级。组件组指的是与一个相同的功能关联的相互依赖的一组组件。组里的所有组件使用相同的组ID和优先级。如果组里的一个组件丢失了资源并停止运行,他们所共同提供的功能也会结束。这种情况下,同一组的所有其他组件应该转移到<code>OMX_StateLoaded</code>。组件仅有一个特定的<code>nGroupID</code>的行为时原子的。</p>
<p><code>OMX_PRIORITYMGMTTYPE</code>定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> OMX_PRIORITYMGMTTYPE {</div><div class="line"> OMX_U32 nSize;</div><div class="line"> OMX_VERSIONTYPE nVersion;</div><div class="line"> OMX_U32 nGroupPriority;</div><div class="line"> OMX_U32 nGroupID;</div><div class="line">} OMX_PRIORITYMGMTTYPE;</div></pre></td></tr></table></figure>
<p>#####3.1.2.5.1 nGroupPriority<br>`nGroupPriority`的值为组件组的优先级。如果组件被指定了这个类型的参数,那么组件所在的组的组件优先级也是这个值。根据定义,0代表了组件组的最高优先级。</p>
<p>指定组件组的具体机制不再本文档讨论范围。</p>
<p>#####3.1.2.5.2 nGroupID<br>`nGroupID`的值是同一个组件组里所有组件的唯一ID。</p>
<p>####3.1.2.6 OMX_BUFFERHEADERTYPE<br>在一个单一端口的上下文中,每一个数据buffer拥有一个相关联的头,包括了buffer的元信息。IL客户端与每一个与之通信的端口共享buffer头。同理,每一个管道两头的两个端口共享buffer头。另外,如果一个buffer传输到多个端口将buffer头分到每一个端口上去。buffer头的定义如下。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> OMX_BUFFERHEADERTYPE</div><div class="line">{</div><div class="line"> OMX_U32 nSize;</div><div class="line"> OMX_VERSIONTYPE nVersion;</div><div class="line"> OMX_U8* pBuffer;</div><div class="line"> OMX_U32 nAllocLen;</div><div class="line"> OMX_U32 nFilledLen;</div><div class="line"> OMX_U32 nOffset;</div><div class="line"> OMX_PTR pAppPrivate;</div><div class="line"> OMX_PTR pPlatformPrivate;</div><div class="line"> OMX_U32 nOutputPortPrivate;</div><div class="line"> OMX_U32 nInputPortPrivate;</div><div class="line"> OMX_HANDLETYPE hMarkTargetComponent;</div><div class="line"> OMX_PTR pMarkData;</div><div class="line"> OMX_U32 nTickCount;</div><div class="line"> OMX_TICKS nTimeStamp;</div><div class="line"> OMX_U32 nFlags;</div><div class="line"> OMX_U32 nOutputPortIndex;</div><div class="line"> OMX_U32 nInputPortIndex;</div><div class="line">} OMX_BUFFERHEADERTYPE;</div></pre></td></tr></table></figure>
<p>#####3.1.2.6.1 pBuffer<br><code>pBuffer</code>为buffer中数据存储的真实指针,但并不一定时是有效数据的起始位置。更多信息参考3.1.2.6.4描述的<code>nOffset</code>。</p>
<p>#####3.1.2.6.2 nAllocLen<br><code>nAllocLen</code>为buffer中分配的总大小,包括有效的和未用的字节。</p>
<p>#####3.1.2.6.3 nFilledLen<br><code>nFilledLen</code>为buffer中有效数据的总大小,从<code>pBuffer</code>和<code>nOffset</code>指定的位置开始。</p>
<p>#####3.1.2.6.4 nOffset<br><code>nOffset</code>为从buffer开始计算的有效数据的偏移位置。有效数据的指针可以从<code>nOffset</code>和<code>pBuffer</code>相加得到。</p>
<p>#####3.1.2.6.5 pAppPrivate<br><code>pAppPrivate</code>为指向IL客户端私有结构的指针。</p>
<p>#####3.1.2.6.6 pPlatformPrivate<br><code>pPlatformPrivate</code>为指向平台私有结构的指针。分配buffer头结构的core使用这个指针。</p>
<p>#####3.1.2.6.7 pOutputPortPrivate<br><code>pOutputPortPrivate</code>为使用buffer的输出端口的私有指针。如果buffer头用于输入端口与IL客户端之间的通信,buffer的<code>pOutputPortPrivate</code>则不用定义。</p>
<p>#####3.1.2.6.8 pInputPortPrivate<br><code>pInputPortPrivate</code>为使用buffer的输入端口的私有指针。如果buffer头用于输出端口与IL客户端之间的通信,buffer的<code>pInputPortPrivate</code>则不用定义。</p>
<p>#####3.1.2.6.9 hMarkTargetComponent<br><code>hMarkTargetComponent</code>为处理buffer时需要发出`OMX_EventMark`消息的组件的句柄。一个空的句柄表面buffer没有携带任何标记。<code>OMX_CommandMarkBuffer</code>命令将次句柄传递给标记的组件。标记的组件,将此句柄复制到标记的buffer中。每个处理此buffer的组件应该使用这个句柄和自己向比较,如果相同,则发出标记消息。组件应该在输入buffer和相应的输出buffer中传递这个字段。</p>
<p>#####3.1.2.6.10 pMarkData<br><code>pMarkData</code>指针指向IL客户端特定的数据,与<code>OMX_EventMark</code>发出的消息标志相关联。当收到这个标记时,IL客户端可以使用这个数据来和其他的标记相区别。命令<code>OMX_CommandMarkBuffer</code>提供此指针来标记组件。标记的组件,将此句柄复制到标记的buffer中。组件应该在输入buffer和相应的输出buffer中传递这个字段。</p>
<p>#####3.1.2.6.11 nTickCount<br><code>nTickCount</code>为一个组件和IL客户端可以更新的计时器,为可选条目,不是所有的组件会更新它。`nTickCount`的值以微秒为单位。由于这个值是一个任意起始点的相对值,它不能用于确定绝对时间。</p>
<p>#####3.1.2.6.12 nTimeStamp<br><code>nTimeStamp</code>为buffer中第一个逻辑单元的时间戳。Buffer中后续数据的时间戳可以通过buffer的持续时间和此时间戳相加得到。组件应该在输入buffer和相应的输出buffer中传递这个字段。</p>
<p>#####3.1.2.6.13 nFlags<br><code>nFlags</code>字段包含了buffer的特定的标志,例如EOS标志。组件应该在输入buffer和相应的输出buffer中传递这个字段。标志的列表如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">define</span> OMX_BUFFERFLAG_EOS 0x00000001</span></div><div class="line"><span class="meta">#<span class="meta-keyword">define</span> OMX_BUFFERFLAG_STARTTIME 0x00000002</span></div><div class="line"><span class="meta">#<span class="meta-keyword">define</span> OMX_BUFFERFLAG_DECODEONLY 0x00000004</span></div><div class="line"><span class="meta">#<span class="meta-keyword">define</span> OMX_BUFFERFLAG_DATACORRUPT 0x00000008</span></div><div class="line"><span class="meta">#<span class="meta-keyword">define</span> OMX_BUFFERFLAG_ENDOFFRAME 0x00000010</span></div></pre></td></tr></table></figure>
<p>######3.1.2.6.13.1 OMX_BUFFERFLAG_EOS<br>如果组件的输出端口没有更多的数据发出,则会设置EOS。因此,一个输出端口应该在最后一个发出的buffer上设置EOS,输出端口什么时候停止发送数据由具体的实现决定。</p>
<p>######3.1.2.6.13.2 OMX_BUFFERFLAG_STARTTIME<br>流的源(例如,分离器组件)设置包含流的起始时间戳的buffer<code>OMX_BUFFERFLAG_STARTTIME</code>标志。起始时间戳对应了起始或跳转操作后第一帧数据显示时间。</p>
<p>流的第一个时间戳不一定是起始时间。例如,在搜索一个特定视频帧的情况下,目标帧可能是一个帧间帧。因此,流的第一帧应该是在目标帧之前的帧内帧。在目标帧所依赖的帧重建完毕后,才能发生目标帧的起始时间。</p>
<p><code>OMX_BUFFERFLAG_STARTTIME</code>标志直接和buffer的时间戳向关联。因此,buffer数据和<code>OMX_BUFFERFLAG_STARTTIME</code>标志的关系和传输和时间戳完全一致。</p>
<p>时钟组件收到一个带有<code>STARTTIME</code>标志的buffer应该在它的同步端口上使用<code>OMX_ConfigTimeClientStartTime</code>调用<code>OMX_SetConfig</code>来传递buffer的时间戳。</p>
<p>######3.1.2.6.13.3 OMX_BUFFERFLAG_DECODEONLY<br>流的源头(例如,一个分离器组件)设置一个只解码不显示的buffer<code>OMX_BUFFERFLAG_DECODEONLY</code> 标志。这个标志用于,源跳转到一个帧间帧时,需要首先解出目标所依赖的帧。在这个例子中,源需要将目标所依赖的帧发出但标记他们只能被解码。</p>
<p><code>OMX_BUFFERFLAG_DECODEONLY</code>标记和buffer数据相关联,传输的行为和时间戳完全一致。显示数据的组件应该忽略所有设置了<code>OMX_BUFFERFLAG_DECODEONLY</code>标志的buffer。</p>
<p>######3.1.2.6.13.4 OMX_BUFFERFLAG_DATACORRUPT<br>当IL客户端识别buffer相关的数据损坏时设置<code>OMX_BUFFERFLAG_DATACORRUPT</code>标志位。</p>
<p>######3.1.2.6.13.5 OMX_BUFFERFLAG_ENDOFFRAME<br><code>OMX_BUFFERFLAG_ENDOFFRAME</code>是一个可选的标志位,buffer playload中包含帧结束的最后一个字节时由输出端口设置。任何一个在输出端口上实现了设置<code>OMX_BUFFERFLAG_ENDOFFRAME</code>标志的组件应该为输出端口发出的每一个包含EOF的buffer设置这个标志。没有buffer payload可以包含两个独立的帧。</p>
<p>这些限制保证了从输出端口接受到数据的输入端口能够不通过额外的处理检测到EOF。也保证了如果输出端口支持这个标志的话,输入端口能轻易的通过标志位的有或无检测第一帧是否传输完。</p>
<p>####3.1.2.6.14 nOutputPortIndex<br><code>nOutputPortIndex</code>包含了使用buffer的输出端口的索引。如果一个buffer头用于和IL端口上的输入端口通信的话,此值不用定义。</p>
<p>#####3.1.2.6.15 nInputPortIndex<br><code>nInputPortIndex</code>包含了使用buffer的输入端口的索引。如果buffer头用于和IL客户端通信的输出端口,此值不用定义。</p>
<p>####3.1.2.7 OMX_PORT_PARAM_TYPE<br>组件用<code>OMX_PORT_PARAM_TYPE</code>结构来定义特定域上的端口数量和起始端口索引。</p>
<p><code>OMX_PORT_PARAM_TYPE</code>定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> OMX_PORT_PARAM_TYPE {</div><div class="line"> OMX_U32 nSize;</div><div class="line"> OMX_VERSIONTYPE nVersion;</div><div class="line"> OMX_U32 nPorts;</div><div class="line"> OMX_U32 nStartPortNumber;</div><div class="line">} OMX_PORT_PARAM_TYPE;</div></pre></td></tr></table></figure>
<p>#####3.1.2.7.1 nPorts<br><code>nPorts</code>为组件给定端口域(音频,视频,图像或其他)上的端口数。</p>
<p>#####3.1.2.7.2 nStartPortNumber<br><code>nStartPortNumber</code>为组件给定端口域(音频,视频,图像或其他)上的端口索引。给定域的后续端口按顺序编号从<code>nStartNumber</code>开始。</p>
<p>#####3.1.2.8 OMX_CALLBACKTYPE<br>OpenMAX IL包含了一个回调机制,允许组件可以和IL客户端进行下面的通信:</p>
<ul>
<li>IL客户端发出的异步命令成功,失败或产生错误。命令包括通过<code>OMX_SendCommand</code>和IL客户端发出的<code>EmptyThisBuffer</code>和<code>FillThisBuffer</code>。</li>
<li>和命令无关的错误发生。例如,组件进入了无法回复的错误并且转移到<code>OMX_StateInvalid</code>状态。</li>
</ul>
<p>为了实现回调,OpenMAX IL定义了3个回调函数:一个通用的事件处理程序和两个和数据流相关的回调(<code>EmptyBufferDone</code>和<code>FillBufferDone</code>)</p>
<p>IL客户端负责用回调函数入口填充<code>OMX_CALLBACKTYPE</code>结构并在初始化的时候传递给OpenMAX core,通常在函数<code>OMX_GetHandle</code>中。</p>
<p><code>OMX_CALLBACKTYPE</code>定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> OMX_CALLBACKTYPE</div><div class="line">{</div><div class="line"> OMX_ERRORTYPE (*EventHandler)(</div><div class="line"> OMX_IN OMX_HANDLETYPE hComponent,</div><div class="line"> OMX_IN OMX_PTR pAppData,</div><div class="line"> OMX_IN OMX_EVENTTYPE eEvent,</div><div class="line"> OMX_IN OMX_U32 nData1,</div><div class="line"> OMX_IN OMX_U32 nData2,</div><div class="line"> OMX_IN OMX_PTR pEventData);</div><div class="line"> OMX_ERRORTYPE (*EmptyBufferDone)(</div><div class="line"> OMX_IN OMX_HANDLETYPE hComponent,</div><div class="line"> OMX_IN OMX_PTR pAppData,</div><div class="line"> OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);</div><div class="line"> OMX_ERRORTYPE (*FillBufferDone)(</div><div class="line"> OMX_IN OMX_HANDLETYPE hComponent,</div><div class="line"> OMX_IN OMX_PTR pAppData,</div><div class="line"> OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);</div><div class="line">} OMX_CALLBACKTYPE;</div></pre></td></tr></table></figure>
<p>#####3.1.2.8.1 EventHandler<br>组件使用事件处理函数方法来通知IL客户端什么时候一个所感兴趣的事件在组件内部发生了。枚举类型<code>OMX_EVENTTYPE</code>定义了OpenMAX IL事件的集合,可以参看每中事件的定义。<code>nData1</code>携带了完成事件的<code>OMX_COMMANDTYPE</code> 值或是<code>OMX_ERRORTYPE</code>的错误类型。<code>nData2</code>携带了更多的事件参数,例如,<code>OMX_STATETYPE</code>。<code>pEventData</code>包含了事件具体的数据。<code>pEventData</code>指针可能包含了额外的与时间有关的数据(例如,标记特定数据)。事件处理函数的调用是阻塞的,所有IL客户端应该在5个毫秒内完成响应,以免长时间阻塞住组件。</p>
<p>方法<code>EventHandler</code>定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">OMX_ERRORTYPE(* OMX_CALLBACKTYPE::EventHandler)(</div><div class="line"> OMX_IN OMX_HANDLETYPE hComponent,</div><div class="line"> OMX_IN OMX_PTR pAppData,</div><div class="line"> OMX_IN OMX_EVENTTYPE eEvent,</div><div class="line"> OMX_IN OMX_U32 nData1,</div><div class="line"> OMX_IN OMX_U32 nData2,</div><div class="line"> OMX_IN OMX_PTR pEventData)</div></pre></td></tr></table></figure>
<p>参数定义如下:</p>
<table>
<thead>
<tr>
<th>参数</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>hComponent</em></td>
<td>调用此函数的组件句柄。</td>
</tr>
<tr>
<td>̛<em>eEvent</em></td>
<td>组件和IL客户端通信的事件。</td>
</tr>
<tr>
<td><em>nData1</em></td>
<td>第一个事件特定的整型参数。表3-7描述了在每个事件上下文中的意义。</td>
</tr>
<tr>
<td><em>nData2</em></td>
<td>第二个事件特定的整型参数。表3-7描述了在每个事件上下文中的意义。如果没有用,默认值为0.</td>
</tr>
<tr>
<td><em>pEventData</em></td>
<td>指向事件特定数据的指针。表3-7描述了在每个事件上下文中的意义。</td>
</tr>
</tbody>
</table>
<p><strong>表 3-7 每一种事件所用的参数列表</strong></p>
<table>
<thead>
<tr>
<th>eEvent</th>
<th>nData1</th>
<th>nData2</th>
<th>pEventData</th>
</tr>
</thead>
<tbody>
<tr>
<td>OMX_EventCmdComplete</td>
<td>OMX_CommandStateSet</td>
<td>状态切换完成</td>
<td>无</td>
</tr>
<tr>
<td></td>
<td>OMX_CommandFlush</td>
<td>端口索引</td>
<td>无</td>
</tr>
<tr>
<td></td>
<td>OMX_CommandPortDisable</td>
<td>端口索引</td>
<td>无</td>
</tr>
<tr>
<td></td>
<td>OMX_CommandPortEnable</td>
<td>端口索引</td>
<td>无</td>
</tr>
<tr>
<td></td>
<td>OMX_CommandMarkBuffer</td>
<td>端口索引</td>
<td>无</td>
</tr>
<tr>
<td>OMX_EventError</td>
<td>错误代码</td>
<td>0</td>
<td>无</td>
</tr>
<tr>
<td>OMX_EventMark</td>
<td>0</td>
<td>0</td>
<td>标记相连的数据(如果有的话)</td>
</tr>
<tr>
<td>OMX_EventPortSettingsChanged</td>
<td>端口索引</td>
<td>0</td>
<td>无</td>
</tr>
<tr>
<td>OMX_EventBufferFlag</td>
<td>端口索引</td>
<td><code>nFlags</code>不可变</td>
<td>无</td>
</tr>
<tr>
<td>OMX_EventResourcesAcquired</td>
<td>0</td>
<td>0</td>
<td>无</td>
</tr>
</tbody>
</table>
<p><strong>表 3-7. 事件参数用法</strong></p>
<p>#####3.1.2.8.2 EmptyBufferDone<br>组件使用回调<code>EmptyBufferDone</code>从一个输入端口返回传递一个buffer给IL客户端。组件设置buffer头中的<code>nOffset</code>和<code>nFilledLength</code>值来反应buffer中被消耗的部位。例如,如果完全被消耗,则<code>nFilledLength</code>设置为0。</p>
<p>为了加快执行组件和IL客户端之间的数据流动,组件在下面情况下使用<code>EmptyBufferDone</code>方法把输入buffer返回给IL客户端:</p>
<ul>
<li>IL客户端命令状态由<code>OMX_StateExecuting</code>或<code>OMX_StatePause</code>转移到<code>OMX_StateIdle</code> 或<code>OMX_StateInvalid</code>。</li>
<li>IL客户端清空或禁用端口。</li>
</ul>
<p><code>EmptyBufferDone</code>为阻塞方法,应该在5毫秒以内返回。因此, IL客户端在调用期间可能不选择填充缓冲区,而在调用之外排队处理。</p>
<p>方法<code>EmptyBufferDone</code>定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">OMX_ERRORTYPE(* OMX_CALLBACKTYPE::EmptyBufferDone)(</div><div class="line"> OMX_OUT OMX_HANDLETYPE hComponent,</div><div class="line"> OMX_OUT OMX_PTR pAppData,</div><div class="line"> OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)</div></pre></td></tr></table></figure>
<p>The parameters are as follows.</p>
<table>
<thead>
<tr>
<th>参数</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>hComponent</em></td>
<td>调用此函数的组件句柄。</td>
</tr>
<tr>
<td><em>pAppData</em></td>
<td>指向IL客户端定义数据的指针。</td>
</tr>
<tr>
<td><em>pBuffer</em></td>
<td>指向消耗或返回的<code>OMX_BUFFERHEADERTYPE</code>结构类型的指针。</td>
</tr>
</tbody>
</table>
<p>#####3.1.2.8.3 FillBufferDone<br>组件使用回调<code>FillBufferDone</code>从输出端口返回数据给IL客户端。组件设置buffer头中的<code>nOffset</code>和<code>nFilledLength</code>值来反应buffer中被填充的部位。例如,如果没有数据,则<code>nFilledLength</code>设置为0。</p>
<p>为了加快执行组件和IL客户端之间的数据流动,组件在下面情况下使用此方法把输出buffer返回给IL客户端:</p>
<ul>
<li>IL客户端命令状态由<code>OMX_StateExecuting</code>或<code>OMX_StatePause</code>转移到<code>OMX_StateIdle</code> 或<code>OMX_StateInvalid</code>。</li>
<li>IL客户端清空或禁用端口。</li>
</ul>
<p><code>FillBufferDone</code>为阻塞方法,应该在5毫秒以内返回。因此, IL客户端在调用期间可能不选择填充缓冲区,而在调用之外排队处理。</p>
<p><code>FillBufferDone</code>定义如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">OMX_ERRORTYPE(* OMX_CALLBACKTYPE::FillBufferDone)(</div><div class="line"> OMX_OUT OMX_HANDLETYPE hComponent,</div><div class="line"> OMX_OUT OMX_PTR pAppData,</div><div class="line"> OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)</div></pre></td></tr></table></figure>
<p>参数定义如下:</p>
<table>
<thead>
<tr>