bytedeco/javacv

How to add cover picture to audio and video?

Open

#1,478 opened on Jul 29, 2020

View on GitHub
 (3 comments) (0 reactions) (0 assignees)Java (1,583 forks)batch import
help wantedquestion

Repository metrics

Stars
 (6,985 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

This is my code, but it doesn't work. The log is at the en. log -> Stream #0:2: Video: mjpeg, yuvj444p, 1920x1080, q=2-31, 400 kb/s, 30 fps, 30 tbn, 30 tbc (attached pic)

        FFmpegFrameRecorderPlus recorder = new FFmpegFrameRecorderPlus("D:\\video\\fengmian\\111.mp4", 1920, 1080);
	recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
	recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
	recorder.setFrameRate(25);
	recorder.setFormat("mp4");
	recorder.setAudioOption("crf", "0");
	recorder.setAudioQuality(0);
	recorder.setAudioBitrate(192000);
	recorder.setSampleRate(44100);
	recorder.setAudioChannels(2);
	recorder.setAudioCodec(avcodec.AV_CODEC_ID_MP3);
	recorder.start();
	try {
		BufferedImage read = ImageIO.read(new File("D:\\video\\3.jpg"));
		Java2DFrameConverter converter = new Java2DFrameConverter();
		Frame frame = converter.getFrame(read);
		for (int i = 0; i < 250; i++) {
			recorder.record(frame);
		}

		String filename = recorder.getFilename();
		AVFormatContext oc = recorder.getAVFormatContext();
		AVStream video_st = avformat_new_stream(oc, null);
		System.out.println("filename: " + recorder.getFilename() + ", index: " + video_st.index());
		
		read = ImageIO.read(new File("D:\\video\\1.jpg"));
		converter = new Java2DFrameConverter();
		frame = converter.getFrame(read);
		int width = frame.imageWidth;
		int height = frame.imageHeight;
		int depth = frame.imageDepth;
		int stride = frame.imageStride;
		BytePointer data = new BytePointer((ByteBuffer) frame.image[0]).position(0); // new BytePointer((ByteBuffer)image[0]).position(0)
								   
		AVBufferRef avBufferRef = new AVBufferRef(data);
		video_st.attached_pic().buf(avBufferRef);
		video_st.attached_pic().data(avBufferRef.data());
		video_st.attached_pic().stream_index(video_st.index());
		video_st.attached_pic().flags(avcodec.AV_CODEC_FLAG_GLOBAL_HEADER);
		video_st.disposition(avformat.AV_DISPOSITION_ATTACHED_PIC);
		video_st.codecpar().codec_type(avutil.AVMEDIA_TYPE_VIDEO);
		video_st.codecpar().codec_id(avcodec.AV_CODEC_ID_MJPEG);

		AVCodec video_codec;
		if ((video_codec = avcodec_find_encoder(avcodec.AV_CODEC_ID_MJPEG)) == null) {
			throw new Exception("avcodec_find_encoder() error: Video codec not found.");
		}
		AVCodecContext video_c;
		if ((video_c = avcodec_alloc_context3(video_codec)) == null) {
			throw new Exception("avcodec_alloc_context3() error: Could not allocate video encoding context.");
		}
		
        video_c.codec_id(video_codec.id());
		video_c.codec_type(video_codec.type());
        video_c.bit_rate(400000);
        video_c.width(1920);
        video_c.height(1080);
        video_c.pix_fmt(avutil.AV_PIX_FMT_YUVJ444P);

		video_c.profile(AVCodecContext.FF_PROFILE_H264_CONSTRAINED_BASELINE);
		video_c.flags(video_c.flags() | AV_CODEC_FLAG_GLOBAL_HEADER);
		video_c.thread_count(0);
		
		int ret = -1;
        if ((ret = avcodec_parameters_from_context(video_st.codecpar(), video_c)) < 0) {
            throw new Exception("avcodec_parameters_from_context() error: Could not copy the video stream parameters.");
        }
		
		AVRational frame_rate = av_d2q(30, 1001000);
		AVRational time_base = avutil.av_inv_q(frame_rate);
		video_c.time_base(time_base);
		
		video_st.time_base(time_base);
		video_st.avg_frame_rate(frame_rate);
		video_st.codec().time_base(time_base);

		AVDictionary options = new AVDictionary(null);
        avcodec_open2(video_c, video_codec, options);
        av_dict_free(options);
        
        AVFrame picture = null, tmp_picture = null;
		if ((picture = av_frame_alloc()) == null) {
			throw new Exception("av_frame_alloc() error: Could not allocate picture.");
		}
		picture.pts(0); 
		if ((tmp_picture = av_frame_alloc()) == null) {
			throw new Exception("av_frame_alloc() error: Could not allocate temporary picture.");
		}
        
		BytePointer picture_buf = null;
		int size = av_image_get_buffer_size(avutil.AV_PIX_FMT_YUVJ444P, 1920, 1080, 1);
		if ((picture_buf = new BytePointer(av_malloc(size))).isNull()) {
			throw new Exception("av_malloc() error: Could not allocate picture buffer.");
		}
		
        AVDictionary metadata = new AVDictionary(null);
        av_dict_set(metadata, "my_title", "my_value", 0);
        av_dict_set(metadata, "my_title1", "my_value1", 0);
        video_st.metadata(metadata);
		
		int step = stride * Math.abs(depth) / 8;
		int pixelFormat = avutil.AV_PIX_FMT_YUVJ444P;

        av_image_fill_arrays(new PointerPointer(tmp_picture), tmp_picture.linesize(), data, pixelFormat, width, height, 1);
        av_image_fill_arrays(new PointerPointer(picture), picture.linesize(), picture_buf, video_c.pix_fmt(), video_c.width(), video_c.height(), 1);
       
		tmp_picture.linesize(0, step);
        tmp_picture.format(pixelFormat);
        tmp_picture.width(width);
        tmp_picture.height(height);
        
		picture.format(pixelFormat);
		picture.width(1920);
		picture.height(1080);
        
		SwsContext img_convert_ctx = null;
		img_convert_ctx = sws_getCachedContext(img_convert_ctx, width, height, pixelFormat, 1920, 1080, video_c.pix_fmt(), SWS_BILINEAR, null, null, (DoublePointer) null);
		if (img_convert_ctx == null) {
			throw new Exception("sws_getCachedContext() error: Cannot initialize the conversion context.");
		}
		sws_scale(img_convert_ctx, new PointerPointer(tmp_picture), tmp_picture.linesize(), 0, height, new PointerPointer(picture), picture.linesize());
		
        AVPacket video_pkt = new AVPacket();
		av_init_packet(video_pkt);
		video_pkt.data(data);
		video_pkt.size((int)data.capacity());
		video_pkt.pos(-1);
		picture.quality(video_c.global_quality());
		
		int[] got_video_packet = new int[1];
		if ((ret = avcodec_encode_video2(video_c, video_pkt, picture, got_video_packet)) < 0) {
			throw new Exception("avcodec_encode_video2() error " + ret + ": Could not encode video packet.");
		}
		
		if (got_video_packet[0] != 0) {
			if (video_pkt.pts() != AV_NOPTS_VALUE) {
				video_pkt.pts(av_rescale_q(video_pkt.pts(), video_c.time_base(), video_st.time_base()));
			}
			if (video_pkt.dts() != AV_NOPTS_VALUE) {
				video_pkt.dts(av_rescale_q(video_pkt.dts(), video_c.time_base(), video_st.time_base()));
			}
		}
		picture.pts(picture.pts() + 1); // magic required by libx264
		avformat.av_interleaved_write_frame(oc, video_pkt);
		av_packet_unref(video_pkt);
        if (av_log_get_level() >= AV_LOG_INFO) {
			av_dump_format(oc, 0, filename, 1);
		}
	} catch (Exception e) {
		LOGGER.error("=> error: ",e);
	} finally {
		recorder.close();
	}

=================== log ===================== filename: D:\video\fengmian\111.mp4, index: 2 [libx264 @ 0000000022c9ca40] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 [libx264 @ 0000000022c9ca40] profile High, level 4.0, 4:2:0, 8-bit [libx264 @ 0000000022c9ca40] 264 - core 159 - H.264/MPEG-4 AVC codec - Copyleft 2003-2019 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=18 lookahead_threads=3 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=abr mbtree=1 bitrate=400 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 Output #0, mp4, to 'D:\video\fengmian\111.mp4': Metadata: encoder : Lavf58.29.100 Stream #0:0: Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1920x1080, q=2-31, 400 kb/s, 25 fps, 12800 tbn, 25 tbc Metadata: my_title2 : my_value2 Stream #0:1: Audio: mp3 (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 192 kb/s [swscaler @ 000000002641b040] Warning: data is not aligned! This can lead to a speed loss [swscaler @ 000000005fdb5ac0] deprecated pixel format used, make sure you did set range correctly [mp4 @ 0000000022c974c0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 94720 >= 0 Output #0, mp4, to 'D:\video\fengmian\111.mp4': Metadata: encoder : Lavf58.29.100 Stream #0:0: Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1920x1080, q=2-31, 400 kb/s, 25 fps, 12800 tbn, 25 tbc Metadata: my_title2 : my_value2 Stream #0:1: Audio: mp3 (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 192 kb/s Stream #0:2: Video: mjpeg, yuvj444p, 1920x1080, q=2-31, 400 kb/s, 30 fps, 30 tbn, 30 tbc (attached pic) Metadata: my_title : my_value my_title1 : my_value1 [libx264 @ 0000000022c9ca40] frame I:1 Avg QP:33.69 size: 51776 [libx264 @ 0000000022c9ca40] frame P:63 Avg QP:28.63 size: 4139 [libx264 @ 0000000022c9ca40] frame B:186 Avg QP:40.11 size: 166 [libx264 @ 0000000022c9ca40] consecutive B-frames: 0.8% 0.0% 0.0% 99.2% [libx264 @ 0000000022c9ca40] mb I I16..4: 15.6% 69.6% 14.7% [libx264 @ 0000000022c9ca40] mb P I16..4: 0.0% 0.4% 0.0% P16..4: 6.8% 0.6% 0.9% 0.0% 0.0% skip:91.3% [libx264 @ 0000000022c9ca40] mb B I16..4: 0.0% 0.0% 0.0% B16..8: 2.2% 0.0% 0.0% direct: 0.0% skip:97.8% L0: 0.7% L1:99.3% BI: 0.0% [libx264 @ 0000000022c9ca40] final ratefactor: 30.00 [libx264 @ 0000000022c9ca40] 8x8 transform intra:74.5% inter:66.6% [libx264 @ 0000000022c9ca40] coded y,uvDC,uvAC intra: 53.1% 32.6% 5.4% inter: 0.9% 0.9% 0.1% [libx264 @ 0000000022c9ca40] i16 v,h,dc,p: 11% 48% 7% 33% [libx264 @ 0000000022c9ca40] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 15% 20% 25% 6% 8% 5% 8% 5% 8% [libx264 @ 0000000022c9ca40] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 20% 22% 17% 8% 10% 6% 8% 3% 5% [libx264 @ 0000000022c9ca40] i8c dc,h,v,p: 69% 23% 6% 2% [libx264 @ 0000000022c9ca40] Weighted P-Frames: Y:0.0% UV:0.0% [libx264 @ 0000000022c9ca40] ref P L0: 87.8% 6.2% 4.2% 1.8% [libx264 @ 0000000022c9ca40] ref B L0: 73.7% 26.3% [libx264 @ 0000000022c9ca40] ref B L1: 81.0% 19.0% [libx264 @ 0000000022c9ca40] kb/s:274.65

Contributor guide