目录
相机拍摄的画面通过local socket 获取,所以C++的代码可以轻易的获取到每一帧视频数据,需要通过JNI 让 Android显示出来,方法有两种,一种是在Android内创建回调函数使用Bitmap 和ImageView 进行赋值显示,另一种也就是ChatGPT完成的,Android将surface 传递到JNI层内,C++来完成赋值和渲染,后者效率更高。
本文通过和ChatGPT的对话来描述代码的实现过程。
礼貌性问候一下。

开始吧:

MediaPlayer mediaPlayer = new MediaPlayer();
SurfaceView surfaceView = findViewById(R.id.surface_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
mediaPlayer.setDataSource("http://your_video_stream.mp4");
mediaPlayer.setDisplay(surfaceHolder);
mediaPlayer.prepare();
mediaPlayer.start();


<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
SurfaceView surfaceView = findViewById(R.id.surface_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
#include <jni.h>
#include <android/native_window_jni.h>
#include <android/native_window.h>
#include <unistd.h>
// ...
extern "C"
JNIEXPORT void JNICALL
Java_com_example_NativeVideoPlayer_playVideo(JNIEnv *env, jobject instance, jobject surface) {
ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
ANativeWindow_setBuffersGeometry(window, 720, 480, WINDOW_FORMAT_RGBA_8888);
while (true) {
// Capture and decode the video stream
// ...
// Render the decoded video frame to the surface
// ...
// Sleep for a short period of time
usleep(16000);
}
ANativeWindow_release(window);
}
public class NativeVideoPlayer {
static {
System.loadLibrary("native-video-player");
}
public native void playVideo(SurfaceHolder surfaceHolder);
}
// ...
NativeVideoPlayer player = new NativeVideoPlayer();
player.playVideo(surfaceHolder);
整体思路是创建一个surface 然后将surface 的 surface holder 传递到 JNI。
但是没有写如何赋值给surface holder 那我们继续问。

jobject surface = env->GetObjectField(surfaceHolder, surfaceFieldID);
// ...
ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
//...
ANativeWindow_setBuffersGeometry(nativeWindow, width, height, format);
//...
ANativeWindow_Buffer buffer;
if (ANativeWindow_lock(nativeWindow, &buffer, NULL) == 0) {
// Assign video stream buffer to the ANativeWindow
// ...
ANativeWindow_unlockAndPost(nativeWindow);
}

if (ANativeWindow_lock(nativeWindow, &buffer, NULL) == 0) {
// Assign video stream buffer to the ANativeWindow
uint8_t *dst = static_cast<uint8_t *>(buffer.bits);
memcpy(dst, yuvBuffer, buffer.stride * buffer.height);
ANativeWindow_unlockAndPost(nativeWindow);
}
到这里基本的代码已经全部写出来了,只需要每次把图像数据写入 到 window 的buffer 中就好。
但是难免有什么不理解或者不对的地方,那我们就继续让它答疑解惑吧。
首先有一个问题,就是我没有从surfaceHolder找到surface。
jclass surfaceHolderClass = env->GetObjectClass(surfaceHolder);
jfieldID surfaceFieldID = env->GetFieldID(surfaceHolderClass, "mSurface", "Landroid/view/Surface;");
jobject surface = env->GetObjectField(surfaceHolder, surfaceFieldID);


然后我就去找新的接口,发现一个getSurface的接口。我自己做了下面的调整:
jmethodID getSurfaceMethodID = env->GetMethodID(surface_hoder_class, "getSurface", "()Landroid/view/Surface;");
jobject surface = env->CallObjectMethod(surface_holder, getSurfaceMethodID);
if(surface == nullptr){}
然后反问它

剩下的就是学习和真的答疑解惑了:



到这里应该就结束了
.
我其实画蛇添足还出了一个问题,ChatGPT 没帮我解决我自己找到的,后来我告诉机器人,下次遇到这样的事情,可以提醒一下其他人,看吧:

因为用到OpenGL 所以要加载一些依赖项。

我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack