# media framworks
opencore:
begin with PacketVideo
av sync with master clock
sink-node
parallel parser/decoder/sink
dropped in android 2.3 (died)
stagefright:
begin with android 2.1
video sync with audio callback data's timestamp.
callback and videoevent
serial parser/decoder/sink
openMAX:
begin with android 2.3
fill buffer, empty buffer.
android.media.MediaCodec
begin with android 4.1
supported containers: mp4, 3gpp, and mkv
cpp calls java: http://git.videolan.org/?p=vlc.git;a=tree;f=modules/codec/omxil
gstreamer:
autoconnect pipeline components
recognize input streams
vaapisink get the raw yuv planes
dmabuf
use VPP for hwaccel transfers to dma_buf imported buffers
hardware optimization -- http://elinux.org/images/7/71/Elc2013_Matsubara.pdf
opengl experiences -- https://vec.io/posts/use-android-hardware-decoder-with-omxcodec-in-ndk
https://github.com/yixia/FFmpeg-Android/blob/master/FFmpeg-Android.sh
http://docs.gstreamer.com/display/GstSDK/Playback+tutorial+8%3A+Hardware-accelerated+video+decoding
http://gstreamer.freedesktop.org/data/pkg/android/1.6.2/gstreamer-1.0-android-armv7-1.6.2.tar.bz2
frameworks/av/include/media/stagefright/MediaSource.h
frameworks/av/media/libstagefright/OMXCodec.cpp
frameworks/av/include/media/stagefright/OMXCodec.h
AVCodec *codec = avcodec_find_decoder_by_name("libx265");
# gstreamer pipeline
pipeline > bin > element
data down:
gst_pad_push
gst_pad_pull_range
gst_buffer_new
gst_buffer_pool_acquire_buffer
buffer = {timestamp, offset, duration, metadata}
event up and down:
element states: NULL, READY, PAUSED, PLAYING
内部GST_MESSAGE_SEGMENT_DONE或pad连接后,设置GST_STATE_READY。
app设置NULL/PLAYING/PAUSED驱动pipeline。
只有preroll足够数据后,才能从READY转换到PAUSED,对于livesource例外。
construct pipeline:
gst_pipeline_new
READY_TO_PAUSED:
gst_bin_add
gst_pad_link
gst_pipeline_get_bus: src -- EOS -- sink -- EOS
gst_element_query: duration, total time.
gst_element_send_event
sink -> SEEK --> FLUSH_START -> FLUSH -> SEGMENT, running_time = 0.
gst_pad_set_chain_function(audiosink)
gst-launch.c main -> gst_parse_launch (pipeline_string, &err);
# eg. overlay text on raw video
depends: freetype, harfbuzz/uniscribe/CoreText, cairo, pango (1999, Raph Levien -- Inconsolata).
videotestsrc ! video/x-raw,width=320,height=480,pixel-aspect-ratio=2/1 ! textoverlay text=Hello font-desc=72 ! xvimagesink
gst-launch \
filesrc location=test.mpg \
! decodebin2 name=demuxer \
demuxer. \
! textoverlay text=Hello \
! x264enc ! muxer. \
demuxer. ! audioconvert ! vorbisenc ! muxer. \
matro?skamux name=muxer \
! filesink location=output.mkv
vorbisenc to faac and matroskamux to mpegtsmux to get output.mpg
clockoverlay time-format="%H:%M:%S"
#changes the colors and adds scratches and dust
gst-launch-1.0 -m videotestsrc ! agingtv ! videoconvert ! autovideosink
gst-launch filesrc location=file.jpg ! jpegdec ! imagefreeze ! mfw_isink.
#debug output
in source code:
GST_DEBUG_CATEGORY (my_cat);
GST_DEBUG_CATEGORY_INIT (my_cat, "abcplugin", 0, "abcplugin");
GST_INFO(): 3 (NONE:0, ERROR:1, WARNING:2, DEBUG:4, LOG:5)
print <=3 of abcplugin, <=4 of yy prefix, <=2 of other plugins:
GST_DEBUG=2,abcplugin:3,yy*:4
# dump pipeline
in gst-launch:
export GST_DEBUG_DUMP_DOT_DIR=.
gst-launch audiotestsrc num-buffers=1000 ! fakesink sync=false
in source code:
compile without GST_DISABLE_GST_DEBUG
export GST_DEBUG_DUMP_DOT_DIR=.
GST_DEBUG_BIN_TO_DOT_FILE_TS(pipeline, GST_DEBUG_GRAPH_SHOW_ALL, "myout");
# write plugin
宏GST_PLUGIN_DEFINE用于定义一个plugin的入口点plugin_init和元数据。同时,它用于输出(export)一个plugin,这样它就就可以被其他应用程序使用。
例如:
static void init(void){
gst_element_register(plugin, feature1_name);
}
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
name,
"my plugin description",
init,
VERSION,
GST_LICENSE,
GST_PACKAGE_NAME,
GST_PACKAGE_ORIGIN)
GST_PLUGIN_DEFINE 根据GST_PLUGIN_BUILD_STATIC展开为静态形式:
void gst_plugin_name_register(void){
gst_plugin_register_static(name, init);
}
或动态库形式(*.so):
GstPluginDesc gst_plugin_desc = {##name, init};
gst_registry_get()返回全局变量_gst_registry_default,init_post注册内置元件以及加载标准plugins(插件)。
gst_init -> gst_init_check -> init_post
gst_object_get_type
gst_element_get_type
gst_bus_get_type
gst_update_registry -> load_plugin_func
load_plugin_func(filename)
gst_plugin_load_file
gst_registry_add_plugin (gst_registry_get(), plugin)
gst_plugin_load_file(filename) -> _priv_gst_plugin_load_file_for_registry:
module = g_module_open (GST_PLUGIN_PATH##filename, G_MODULE_BIND_LOCAL);
g_module_symbol (module, "gst_plugin_desc", &ptr);
desc = (GstPluginDesc *) ptr;
GstPlugin *plugin = g_object_newv (GST_TYPE_PLUGIN, 0, NULL);
return plugin;
gst_registry_add_plugin(registry, plugin):
registry->priv->plugins = g_list_prepend (registry->priv->plugins, plugin);
g_signal_emit (registry, gst_registry_signals[PLUGIN_ADDED], 0, plugin);
gst_plugin_register_func -> init
gst_plugin_register_static
GstPlugin *plugin = g_object_newv (GST_TYPE_PLUGIN, 0, NULL);
gst_plugin_register_func -> init
# GLib Dynamic Type System
dynamic type system: query for object metadata at runtime.
GTypeInfo:{base, class, instance, value_table}
constructor: base --> class --> instance
copy operatortor: value_table
destructor: dispose refs/finalize free: instance -> class -> base.
# G_DEFINE_TYPE(TN, t_n, T_P) 展开
static void t_n_class_init(TNClass *kclass);
static void t_n_init(TN *self);
static gpointer t_n_parent_class = NULL; //quizz: why need this?
Gtype t_n_get_type(void)
{
static GType type = 0;
if(type == 0){
type = g_type_register_static_simple(T_P, "TN",
sizeof(TNClass), t_n_class_init,
sizeof(TN), t_n_init, 0);
}
return type;
}
/////////////property/////////////
继承关系:
element <- GST_TYPE_OBJECT <- gobject: G_TYPE_INITIALLY_UNOWNED=g_initially_unowned_get_type()
static void t_n_class_init(TNClass *kclass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
object_class->set_property = set_property; //overwrite default
object_class->get_property = get_property;
//object_class->dispose(GObject *gobject);
//object_class->finalize(GObject *gobject);
pspec_add = g_param_spec_uint64 ("add", "Add", "Number of added samples",
0, 4, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_ADD, pspec_add);
element_class->change_state = change_state;
}
static void gst_audio_rate_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstAudioRate *audiorate = GST_AUDIO_RATE (object);
if(PROP_ADD == prop_id){
}
}
static void change_state (GstElement * element, GstStateChange transition)
{
GstAudioRate *audiorate = GST_AUDIO_RATE (element);
if(GST_STATE_CHANGE_PAUSED_TO_READY == transition){
//
}
return GST_ELEMENT_CLASS (t_n_parent_class)->change_state(element, transition);
}
g_signal_connect callback to events.
affect auto-plugger:
gst_plugin_feature_set_rank
GST_RANK_PRIMARY+1 -- enable
GST_RANK_NONE -- disable using this plugin
Static linking with re-locatable archives: -DPIC and -fPIC
libgstreamer_android.so --whole-archive
# todo
gst_type_find_helper_get_range
/*
apt-get install libgstreamer1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev
gcc gst-hello.c -g $(pkg-config --cflags --libs gstreamer-1.0)
GST_DEBUG="*:3" ./a.out
gst-inspect-1.0
...
Total count: 196 plugins, 666 features
grep -nr 'gst_element_register' --include=*.c ./
gst-launch-1.0 playbin uri=file://$(pwd)/file.ogg
gst-launch-1.0 filesrc location=file.ogg ! decodebin ! tee name=d \
d. ! queue ! audioconvert ! audioresample ! autoaudiosink \
d. ! queue ! audioconvert ! monoscope ! videoconvert ! ximagesink \
d. ! queue ! goom ! videoconvert ! xvimagesink
transcode:
gst-launch-1.0 filesrc location=out0.mp4 ! decodebin name=dmux ! queue ! audioconvert ! lamemp3enc ! filesink location=out.mp3
gst-launch-1.0 filesrc location=out0.mp4 ! decodebin name=dmux ! queue ! audioconvert ! lamemp3enc ! mux. dmux. ! queue ! x264enc ! mpegtsmux name=mux ! queue ! filesink location=out.ts
“! mux.” means link to mpegtsmux
lamemp3enc 需要安装 gstreamer1.0-plugins-ugly
h264 需要安装 gstreamer1.0-libav
转码后是h264+mp3,文件大小是原来的8倍!播放时发现视频dts < pts。
对比ffmpeg转码为mpeg2+mp2, 文件大小是原来的3倍。
gst-launch-1.0 -v audiotestsrc ! goom ! videoconvert ! xvimagesink
v4l2src
#ref
http://wiki.oz9aec.net/index.php/Gstreamer_cheat_sheet
http://gstreamer.freedesktop.org/documentation/
*/
#include
int main(int argc, char *argv[]) {
GstElement *pipeline;
GstBus *bus;
GstMessage *msg;
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Build the pipeline */
pipeline = gst_parse_launch ("playbin uri=http://docs.gstreamer.com/media/sintel_trailer-480p.webm", NULL);
if(!pipeline){
return -1;
}
/* Start playing */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* Wait until error or EOS */
bus = gst_element_get_bus (pipeline);
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* Free resources */
if (msg != NULL)
gst_message_unref (msg);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}