使用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>
View Code

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
");
 46         }
 47         m_pCodecCtx = avcodec_alloc_context3(m_pCodec);
 48         if (m_pCodecCtx == null) {
 49             System.out.println("Could not allocate video codec context
");
 50         }
 51 
 52         pCodecParserCtx = av_parser_init(codec_id);
 53         if (pCodecParserCtx == null) {
 54             System.out.println("Could not allocate video parser context
");
 55         }
 56 
 57         if (avcodec_open2(m_pCodecCtx, m_pCodec, (PointerPointer<Pointer>) null) < 0) {
 58             System.out.println("Could not open codec
");
 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 }
View Code

因为在网上很少有用javacv来解码的例子,只能自己踩坑前行,一点点的测试,所以可能有很多错误或可以优化的地方。

自己项目中用到,以此来记录,便于以后再遇到相同的问题。

原文地址:https://www.cnblogs.com/zh-peng/p/10076590.html