其实是一个用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 "); 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 }
因为在网上很少有用javacv来解码的例子,只能自己踩坑前行,一点点的测试,所以可能有很多错误或可以优化的地方。
自己项目中用到,以此来记录,便于以后再遇到相同的问题。