使用javacv,解码socket接收的H264码流(byte[]),转为yuv处理,最后再合成转为H264
其实是一个用java实现录像的功能,还没有实现,但解码和转码已经可以。
1.maven环境,pom.xml配置
1 <properties>
2 <javacpp.version>1.4.1</javacpp.version>
3 <!-- ffmpeg版本 -->
4 <ffmpeg.version>3.4.2</ffmpeg.version>
5 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
6 <servlet.version>3.1.0</servlet.version>
7 </properties>
8 <dependency>
9 <groupId>org.bytedeco</groupId>
10 <artifactId>javacv-platform</artifactId>
11 <version>${javacpp.version}</version>
12 </dependency>
13 <dependency>
14 <groupId>org.bytedeco</groupId>
15 <artifactId>javacpp</artifactId>
16 <version>${javacpp.version}</version>
17 </dependency>
18 <dependency>
19 <groupId>org.bytedeco.javacpp-presets</groupId>
20 <artifactId>ffmpeg-platform</artifactId>
21 <version>${ffmpeg.version}-${javacpp.version}</version>
22 </dependency>
2.代码
1 package com.br.test;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.File;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.nio.ByteBuffer;
8 import org.bytedeco.javacpp.*;
9 import static org.bytedeco.javacpp.avcodec.*;
10 import static org.bytedeco.javacpp.avformat.*;
11 import static org.bytedeco.javacpp.avutil.*;
12 import static org.bytedeco.javacpp.swscale.*;
13
14 public class NewTest {
15 // Load only once formats and codecs
16 static {
17 av_register_all();
18 // avformat_network_init();
19 avcodec_register_all();
20 }
21 public int codec_id;
22 public AVCodecContext m_pCodecCtx = null; // URL中视频解码部分内容
23 public AVFrame m_pFrame = null; // 全局使用帧对象
24 public AVFrame m_pFrameRGB = null;
25 public AVCodec m_pCodec = null;
26 public AVCodecParserContext pCodecParserCtx = null;
27 public AVPacket packet = null;
28 public SwsContext m_pImageConvertCtx = null; // 构造全局对象,供sws_scale切割图片使用
29 public SwsContext img_convert_ctx = null;
30 public Integer count = 0;
31 public int count_size;
32 public BytePointer cur_ptr;
33 public FileOutputStream os;
34 private ByteArrayOutputStream myByteArrayOutputStream = new ByteArrayOutputStream();
35
36 public NewTest() {
37 System.out.println("init begin");
38
39 m_pFrame = av_frame_alloc();
40 codec_id = AV_CODEC_ID_H264;
41 m_pFrameRGB = av_frame_alloc();
42 m_pCodec = avcodec_find_decoder(codec_id);
43
44 if (m_pCodec == null) {
45 System.out.println("Codec not found\n");
46 }
47 m_pCodecCtx = avcodec_alloc_context3(m_pCodec);
48 if (m_pCodecCtx == null) {
49 System.out.println("Could not allocate video codec context\n");
50 }
51
52 pCodecParserCtx = av_parser_init(codec_id);
53 if (pCodecParserCtx == null) {
54 System.out.println("Could not allocate video parser context\n");
55 }
56
57 if (avcodec_open2(m_pCodecCtx, m_pCodec, (PointerPointer<Pointer>) null) < 0) {
58 System.out.println("Could not open codec\n");
59 }
60 img_convert_ctx = sws_getContext(1920, 1088, AV_PIX_FMT_YUV420P, 1920, 1088, AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR,
61 null, null, (DoublePointer) null);
62
63 packet = new AVPacket();
64
65 packet = av_packet_alloc();
66
67 av_new_packet(packet, 30000);
68
69 int numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGRA, 1920, 1088, 1);
70
71 BytePointer rgbData = new BytePointer(av_malloc(numBytes));
72
73 av_image_fill_arrays(m_pFrameRGB.data(), m_pFrameRGB.linesize(), rgbData, AV_PIX_FMT_BGRA, 1920, 1088, 1);
74
75 System.out.println("init end");
76 }
77
78 public void dec_loop(byte[] H264) {
79
80 ByteBuffer data = ByteBuffer.allocate(H264.length);
81 data.put(H264);
82 int cur_size = H264.length;
83 IntPointer pktSize = new IntPointer(packet.size());
84 BytePointer temp_bp = new BytePointer();
85 while (cur_size > 0) {
86
87 data.flip();
88 int slen = av_parser_parse2(pCodecParserCtx, m_pCodecCtx, temp_bp, pktSize, new BytePointer(data), cur_size,
89 AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
90 packet = packet.size(pktSize.get());
91
92 data.position(slen);
93 data = data.compact();
94 cur_size -= slen;
95
96 if (pktSize.get() == 0) {
97 continue;
98 }
99 packet = packet.data(temp_bp);
100 // for(int i = 0;i <5;i++){
101 // byte b = packet.data().get(i);
102 // System.out.print(byteToHex(b)+" ");
103 // }
104 // System.out.println("------------------------------!!!!------------------"+packet.size());
105 // packet.data().asBuffer();
106
107 int asp = avcodec_send_packet(m_pCodecCtx, packet);
108
109 if (avcodec_receive_frame(m_pCodecCtx, m_pFrame) == 0) {
110 // m_pFrame.data(0);
111 // y = m_pFrame->data[0];1920*1088
112 // u = m_pFrame->data[1];1920*1088/4
113 // v = m_pFrame->data[2];1920*1088/4
114
115 System.err.println(
116 "->>> decode success " + "width :" + m_pFrame.width() + " " + "height :" + m_pFrame.height());
117
118 sws_scale(img_convert_ctx, m_pFrame.data(), m_pFrame.linesize(), 0, m_pCodecCtx.height(),
119 m_pFrameRGB.data(), m_pFrameRGB.linesize());
120 BytePointer by_bgra_data = m_pFrameRGB.data(0);
121 try {
122 // String imgName = "C:/Users/user/Desktop/test/test" + count + ".h264";
123 // saveImg(m_pFrame, imgName);
124 // count++;
125 // for (int i = 0; i < 1920 * 1088 * 4; i++) {
126 // myByteArrayOutputStream.write(by_bgra_data.get(i));
127 // }
128 // if (myByteArrayOutputStream.size() == 1920 * 1088 * 4) {
129 // File file = new
130 // File("C://Users//user//Desktop//test//success.yuv");
131 // if (!file.exists()) {
132 // file.createNewFile();
133 // }
134 // FileOutputStream fe = new FileOutputStream(file, true);
135 // fe.write(myByteArrayOutputStream.toByteArray());
136 // fe.flush();
137 // fe.close();
138 // myByteArrayOutputStream.reset();
139 // }
140 } catch (Exception e) {
141 e.printStackTrace();
142 }
143 }
144 // av_packet_unref(packet);
145 }
146 // av_packet_free(packet);
147 }
148
149 public int saveImg(AVFrame pFrame, String out_file) throws IOException {
150 AVCodec codec = null;
151 AVPacket pkt = null;
152 AVStream pAVStream = null;
153 int ret = -1;
154 AVDictionary avd = new AVDictionary(null);
155 int width = pFrame.width(), height = pFrame.height();
156 // 分配AVFormatContext对象
157 AVFormatContext pFormatCtx = avformat_alloc_context();
158 // 设置输出文件格式
159 pFormatCtx.oformat(av_guess_format("h264", null, null));
160 if (pFormatCtx.oformat() == null) {
161 return -1;
162 }
163 try {
164 // 创建并初始化一个和该url相关的AVIOContext
165 AVIOContext pb = new AVIOContext();
166 if (avio_open(pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {// dont open
167 // file
168 return -1;
169 }
170 pFormatCtx.pb(pb);
171 // 构建一个新stream
172 pAVStream = avformat_new_stream(pFormatCtx, codec);
173 if (pAVStream == null) {
174 return -1;
175 }
176 int codec_id = pFormatCtx.oformat().video_codec();
177 // 设置该stream的信息
178 AVCodecContext pCodecCtx = pAVStream.codec();
179 pCodecCtx.codec_id(codec_id);
180 pCodecCtx.codec_type(AVMEDIA_TYPE_VIDEO);
181 pCodecCtx.pix_fmt(AV_PIX_FMT_YUV420P);
182 pCodecCtx.width(width);
183 pCodecCtx.height(height);
184 pCodecCtx.time_base().num(1);
185 pCodecCtx.time_base().den(25);
186 pCodecCtx.qmin(10);
187 pCodecCtx.qmax(51);
188 pCodecCtx.bit_rate(400000);
189 pCodecCtx.gop_size(12);
190 pCodecCtx.qcompress(0.6f);
191
192 if (pCodecCtx.codec_id() == AV_CODEC_ID_H264) {
193 av_dict_set(avd, "preset", "slow", 0);
194 av_dict_set(avd, "tune", "zerolatency", 0);
195 }
196
197 // Begin Output some information
198 av_dump_format(pFormatCtx, 0, out_file, 1);
199 // End Output some information
200
201 // 查找编码器
202 AVCodec pCodec = avcodec_find_encoder(pCodecCtx.codec_id());
203 if (pCodec == null) {// codec not found
204 return -1;
205 }
206 // 设置pCodecCtx的解码器为pCodec
207 if (avcodec_open2(pCodecCtx, pCodec, avd) < 0) {
208 System.err.println("Could not open codec.");
209 av_dict_free(avd);
210 return -1;
211 }
212
213 // Write Header
214 avformat_write_header(pFormatCtx, (PointerPointer<Pointer>) null);
215
216 // 给AVPacket分配足够大的空间
217 pkt = new AVPacket();
218 int yuvSize = ((width * height) / 2) * 3;
219 if (av_new_packet(pkt, yuvSize) < 0) {
220 return -1;
221 }
222
223 int[] got_picture = { 0 };
224 // encode
225
226 if (avcodec_encode_video2(pCodecCtx, pkt, pFrame, got_picture) >= 0) {
227 System.out.println("got_picture[0]:" + got_picture[0]);
228 if (got_picture[0] == 1) {
229 // flush
230 BytePointer pkt_data = pkt.data();
231 // 输出pkt数据到文件
232 for (int i = 0; i < pkt.size(); i++) {
233 myByteArrayOutputStream.write(pkt_data.get(i));
234 }
235 if (myByteArrayOutputStream.size() == pkt.size()) {
236 File file = new File("C://Users//user//Desktop//test//success.h264");
237 if (!file.exists()) {
238 file.createNewFile();
239 }
240 FileOutputStream fe = new FileOutputStream(file, true);
241 fe.write(myByteArrayOutputStream.toByteArray());
242 fe.flush();
243 fe.close();
244 myByteArrayOutputStream.reset();
245 }
246
247 if ((ret = av_write_frame(pFormatCtx, pkt)) >= 0) {
248 // Write Trailer
249 if (av_write_trailer(pFormatCtx) >= 0) {
250 System.err.println("->>> Encode Successful. pkt.size():" + pkt.size());
251 } else {
252 System.err.println("Encode failed.");
253 }
254 }
255 }
256 }
257 return ret;
258 // 结束时销毁
259 } finally {
260 if (pkt != null) {
261 av_free_packet(pkt);
262 }
263 if (pAVStream != null) {
264 avcodec_close(pAVStream.codec());
265 }
266 if (pFormatCtx != null) {
267 avio_close(pFormatCtx.pb());
268 avformat_free_context(pFormatCtx);
269 }
270 }
271 }
272
273 public static byte[] conver(ByteBuffer byteBuffer) {
274 int len = byteBuffer.limit() - byteBuffer.position();
275 byte[] bytes = new byte[len];
276
277 if (byteBuffer.isReadOnly()) {
278 return null;
279 } else {
280 byteBuffer.get(bytes);
281 }
282 return bytes;
283 }
284
285 public static String byteToHex(byte b) {
286 String hex = Integer.toHexString(b & 0xFF);
287 if (hex.length() < 2) {
288 hex = "0" + hex;
289 }
290 return hex;
291 }
292
293 public static void main(String[] args) {
294 NewTest test = new NewTest();
295 }
296
297 }
因为在网上很少有用javacv来解码的例子,只能自己踩坑前行,一点点的测试,所以可能有很多错误或可以优化的地方。
自己项目中用到,以此来记录,便于以后再遇到相同的问题。
使用javacv,解码socket接收的H264码流(byte[]),转为yuv处理,最后再合成转为H264的更多相关文章
- H264码流打包分析
转自:http://www.360doc.com/content/13/0124/08/9008018_262076786.shtml SODB 数据比特串-->最原始的编码数据 RBSP ...
- H264码流打包分析(精华)
H264码流打包分析 SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若 ...
- H264码流解析及NALU
ffmpeg 从mp4上提取H264的nalu http://blog.csdn.net/gavinr/article/details/7183499 639 /* bitstream fil ...
- H264码流中SPS PPS详解<转>
转载地址:https://zhuanlan.zhihu.com/p/27896239 1 SPS和PPS从何处而来? 2 SPS和PPS中的每个参数起什么作用? 3 如何解析SDP中包含的H.264的 ...
- RTP协议全解析(H264码流和PS流)
转自:http://blog.csdn.net/chen495810242/article/details/39207305 写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个 ...
- (转)RTP协议全解(H264码流和PS流)
写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...
- RTP协议全解(H264码流和PS流)
写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...
- H264编码原理以及I帧、B和P帧详解, H264码流结构分析
H264码流结构分析 http://blog.csdn.net/chenchong_219/article/details/37990541 1.码流总体结构: h264的功能分为两层,视频编码层(V ...
- 从H264码流中获取视频宽高 (SPS帧) 升级篇
之前写过 <从H264码流中获取视频宽高 (SPS帧)> . 但发现很多局限性,而且有时解出来是错误的. 所以重新去研究了. 用了 官方提供的代码库来解析. 花了点时间,从代码库里单独把解 ...
- 从H264码流中获取视频宽高 (SPS帧)
获取.h264视频宽高的方法 花了2个通宵终于搞定.(后面附上完整代码) http://write.blog.csdn.net/postedit/7852406 图像的高和宽在H264的SPS帧中.在 ...
随机推荐
- 利用 LibWebP-NET 解码与编码 WebP 格式图片
此文以后将会在我的新博客更新,有任何疑问可在我的新博文中提出 https://blog.clso.fun/posts/2019-03-02/vb-net-webp.html WebP 格式是谷歌开发并 ...
- 自定义延时关闭弹窗,替代MesssageBox
1,新建一个窗体MessageForm,在里面加一个label控件和timer 2,代码如下: public partial class MessageForm : Form { int t; str ...
- 前台获取枚举的key值
如: Enum ShowPosition { 首页 = 0,一级分类页 = 1,二级分类页 = 2 } 想获得汉字对应的数字,可用GetHashCode() html展示如下:循环枚举 @foreac ...
- Java反射机制介绍
1. 文档概述 Java反射是Java被视为动态(或准动态)语言的一个关键性质,Java反射机制容许程序在运行时加载.探知.使用编译期间完全未知的classes.换言之,Java可以加载一个运行时才得 ...
- Linux巩固记录(5) hadoop 2.7.4下自己编译代码并运行MapReduce程序
程序代码为 ~\hadoop-2.7.4\share\hadoop\mapreduce\sources\hadoop-mapreduce-examples-2.7.4-sources\org\apac ...
- MySQL 主从复制相关参数
列举了MySQL主从复制主要的相关参数 binlog server_id 服务器在集群中唯一标识符 log_bin[=binlog_name] 启动二进制日志 log_bin_index 二进制日志索 ...
- ping端口是否开放(windows,macos,linux)
windows中ping端口:tcping命令 1. tcping 非自带命令,首先安装tcping命令,也可以去官网:http://www.elifulkerson.com/projects/tcp ...
- UI的设计,适配器,以及RecyclerView无法加载的解决办法
这本书里讲到的界面设计都是用最基本的方式实现的,即编写xml文件 所有的控件都具有宽度和高度属性,即android:layout_width和android:layout_height,这两个属性对应 ...
- 01-Linux的基本指令
Linux的基本指令 基础指令(重点) 1.ls指令: 含义:ls(list) 用法1:#ls 含义:列出当前工作目录下的所有文件/文件夹的名称 用法2:#ls 路径 含义:列出指定路径下的所有文件 ...
- cFSMN和FSMN参数规模对比分析
1. FSMN参数规模分析 (1)分析前提: 假设隐藏层单元规模都为n 只分析前向t个时刻的结构,即暂时不考虑双向的结构 只分析向量系数编码,即vFSMN,暂时不考虑sFSMN ...