2023-03-10:YUV420P像素数据编码为JPEG图片,请用go语言实现。

news/2024/12/21 19:30:04/

2023-03-10:YUV420P像素数据编码为JPEG图片,请用go语言实现。

答案2023-03-10:

方法一、使用 github.com/moonfdd/ffmpeg-go 库,基于雷霄骅的代码修改。

方法二、使用golang官方库image/jpeg,yuv420p先转换成rgb,再转换成jpeg。代码是用山寨版的chatgpt生成。

go run ./examples/leixiaohua1020/simplest_ffmpeg_picture_encoder/main.go

方法一,参考了雷霄骅的图像编码器,代码用golang编写。代码如下:

// https://github.com/leixiaohua1020/simplest_ffmpeg_picture_encoder/blob/master/simplest_ffmpeg_picture_encoder/simplest_ffmpeg_picture_encoder.cpp
package mainimport ("fmt""os""os/exec""unsafe""github.com/moonfdd/ffmpeg-go/ffcommon""github.com/moonfdd/ffmpeg-go/libavcodec""github.com/moonfdd/ffmpeg-go/libavformat""github.com/moonfdd/ffmpeg-go/libavutil"
)func main0() (ret ffcommon.FInt) {var pFormatCtx *libavformat.AVFormatContextvar fmt0 *libavformat.AVOutputFormatvar video_st *libavformat.AVStreamvar pCodecCtx *libavcodec.AVCodecContextvar pCodec *libavcodec.AVCodecvar picture_buf *ffcommon.FUint8Tvar picture *libavutil.AVFramevar pkt libavcodec.AVPacketvar y_size ffcommon.FIntvar got_picture ffcommon.FInt = 0var size ffcommon.FIntvar in_file *os.File                    //YUV sourcevar in_w, in_h ffcommon.FInt = 640, 360 //YUV's width and heightvar out_file = "./out/pic.jpg"          //Output filein := "./out/pic.yuv"//是否存在yuv文件_, err := os.Stat(in)if err != nil {if os.IsNotExist(err) {fmt.Println("create yuv file")exec.Command("./lib/ffmpeg", "-i", "./resources/big_buck_bunny.mp4", "-pix_fmt", "yuv420p", in, "-y").CombinedOutput()}}in_file, _ = os.Open(in)if in_file == nil {return -1}libavformat.AvRegisterAll()//Method 1pFormatCtx = libavformat.AvformatAllocContext()//Guess formatfmt0 = libavformat.AvGuessFormat("mjpeg", "", "")pFormatCtx.Oformat = fmt0//Output URLif libavformat.AvioOpen(&pFormatCtx.Pb, out_file, libavformat.AVIO_FLAG_READ_WRITE) < 0 {fmt.Printf("Couldn't open output file.")return -1}//Method 2. More simple//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);//fmt = pFormatCtx->oformat;video_st = pFormatCtx.AvformatNewStream(nil)if video_st == nil {return -1}pCodecCtx = video_st.CodecpCodecCtx.CodecId = fmt0.VideoCodecpCodecCtx.CodecType = libavutil.AVMEDIA_TYPE_VIDEOpCodecCtx.PixFmt = libavutil.AV_PIX_FMT_YUVJ420PpCodecCtx.Width = in_wpCodecCtx.Height = in_hpCodecCtx.TimeBase.Num = 1pCodecCtx.TimeBase.Den = 25//Output some informationpFormatCtx.AvDumpFormat(0, out_file, 1)pCodec = libavcodec.AvcodecFindEncoder(pCodecCtx.CodecId)if pCodec == nil {fmt.Printf("Codec not found.")return -1}if pCodecCtx.AvcodecOpen2(pCodec, nil) < 0 {fmt.Printf("Could not open codec.")return -1}picture = libavutil.AvFrameAlloc()picture.Width = pCodecCtx.Widthpicture.Height = pCodecCtx.Heightpicture.Format = pCodecCtx.PixFmtsize = libavcodec.AvpictureGetSize(pCodecCtx.PixFmt, pCodecCtx.Width, pCodecCtx.Height)picture_buf = (*byte)(unsafe.Pointer(libavutil.AvMalloc(uint64(size))))if picture_buf == nil {return -1}((*libavcodec.AVPicture)(unsafe.Pointer(picture))).AvpictureFill(picture_buf, pCodecCtx.PixFmt, pCodecCtx.Width, pCodecCtx.Height)//Write HeaderpFormatCtx.AvformatWriteHeader(nil)y_size = pCodecCtx.Width * pCodecCtx.Heightpkt.AvNewPacket(y_size * 3)//Read YUV_, err = in_file.Read(ffcommon.ByteSliceFromByteP(picture_buf, int(y_size*3/2)))if err != nil {fmt.Printf("Could not read input file.%s", err)return -1}picture.Data[0] = picture_buf                                                                         // Ypicture.Data[1] = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(picture_buf)) + uintptr(y_size)))     // Upicture.Data[2] = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(picture_buf)) + uintptr(y_size*5/4))) // V//Encoderet = pCodecCtx.AvcodecEncodeVideo2(&pkt, picture, &got_picture)if ret < 0 {fmt.Printf("Encode Error.\n")return -1}if got_picture == 1 {pkt.StreamIndex = uint32(video_st.Index)ret = pFormatCtx.AvWriteFrame(&pkt)}pkt.AvFreePacket()//Write TrailerpFormatCtx.AvWriteTrailer()fmt.Printf("Encode Successful.\n")if video_st != nil {video_st.Codec.AvcodecClose()libavutil.AvFree(uintptr(unsafe.Pointer(picture)))libavutil.AvFree(uintptr(unsafe.Pointer(picture_buf)))}pFormatCtx.Pb.AvioClose()pFormatCtx.AvformatFreeContext()in_file.Close()exec.Command("./lib/ffplay.exe", out_file).Output()if err != nil {fmt.Println("play err = ", err)}return 0
}func main() {os.Setenv("Path", os.Getenv("Path")+";./lib")ffcommon.SetAvutilPath("./lib/avutil-56.dll")ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")ffcommon.SetAvdevicePath("./lib/avdevice-58.dll")ffcommon.SetAvfilterPath("./lib/avfilter-56.dll")ffcommon.SetAvformatPath("./lib/avformat-58.dll")ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")ffcommon.SetAvswscalePath("./lib/swscale-5.dll")genDir := "./out"_, err := os.Stat(genDir)if err != nil {if os.IsNotExist(err) {os.Mkdir(genDir, 0777) //  Everyone can read write and execute}}// go func() {// 	time.Sleep(1000)// 	exec.Command("./lib/ffplay.exe", "rtmp://localhost/publishlive/livestream").Output()// 	if err != nil {// 		fmt.Println("play err = ", err)// 	}// }()main0()
}

方法二,用第1个chatgpt生成golang代码:

// https://chat.forchange.cn/
// YUV420P像素数据编码为JPEG图片,请用go语言实现。package mainimport ("bufio""fmt""image""image/color""image/jpeg""os"
)func main() {// 将YUV420P像素数据读入内存yuvFile, err := os.Open("./out/pic.yuv")if err != nil {fmt.Println(err)return}defer yuvFile.Close()width := 640height := 360yuvData := make([]byte, width*height*3/2)yuvReader := bufio.NewReader(yuvFile)_, err = yuvReader.Read(yuvData)if err != nil {fmt.Println(err)return}// 将YUV420P像素数据转换为RGB格式的图像img := image.NewRGBA(image.Rect(0, 0, width, height))for y2 := 0; y2 < height; y2++ {for x := 0; x < width; x++ {// 从YUV420P像素数据中获取Y、U、V值yIndex := y2*width + xuIndex := width*height + (y2/2)*(width/2) + x/2vIndex := width*height*5/4 + (y2/2)*(width/2) + x/2y3 := float64(yuvData[yIndex])u := float64(yuvData[uIndex]) - 128.0v := float64(yuvData[vIndex]) - 128.0// 将YUV值转换为RGB值r := y3 + 1.402*vg := y3 - 0.344*u - 0.714*vb := y3 + 1.772*u// 将RGB值限制在0-255范围内r = limit(r, 0, 255)g = limit(g, 0, 255)b = limit(b, 0, 255)// 将RGB值保存到图像中img.Set(x, y2, color.RGBA{uint8(r), uint8(g), uint8(b), 255})}}// 将图像编码为JPEG图片并保存到文件中jpegFile, err := os.Create("./out/pic2.jpg")if err != nil {fmt.Println(err)return}defer jpegFile.Close()err = jpeg.Encode(jpegFile, img, nil)if err != nil {fmt.Println(err)return}fmt.Println("JPEG image saved to ./out/pic2.jpg")
}// 将value限制在min和max之间
func limit(value, min, max float64) float64 {if value < min {return min}if value > max {return max}return value
}

方法二,用第2个chatgpt生成golang代码:

// https://chatgpt.zcorky.com/ 第一次失败,第二次成功
// YUV420P像素数据编码为JPEG图片,请用go语言实现。不要用第三方库
package mainimport ("bufio""bytes""fmt""image""image/color""image/jpeg""os"
)func main() {// 将YUV420P像素数据读入内存yuvFile, err := os.Open("./out/pic.yuv")if err != nil {fmt.Println(err)return}defer yuvFile.Close()width := 640height := 360yuvData := make([]byte, width*height*3/2)yuvReader := bufio.NewReader(yuvFile)_, err = yuvReader.Read(yuvData)if err != nil {fmt.Println(err)return}// 假设您已经读取了 YUV420P 格式的像素数据,并将其存储在 data 变量中var yuv []byte = yuvData // YUV420P 数据// 创建一个新的 RGBA 图像rgbaImg := image.NewRGBA(image.Rect(0, 0, width, height))// 将 YUV420P 数据转换为 RGBA 数据for i := 0; i < width*height; i++ {yi := int(yuv[i])ui := int(yuv[width*height+(i/4)])vi := int(yuv[width*height+(width*height/4)+(i/4)])r := float64(yi) + 1.4065*(float64(vi)-128)g := float64(yi) - 0.3455*(float64(ui)-128) - 0.7169*(float64(vi)-128)b := float64(yi) + 1.7790*(float64(ui)-128)if r < 0 {r = 0} else if r > 255 {r = 255}if g < 0 {g = 0} else if g > 255 {g = 255}if b < 0 {b = 0} else if b > 255 {b = 255}rgbaImg.SetRGBA(i%width, i/width, color.RGBA{R: uint8(r),G: uint8(g),B: uint8(b),A: 255,})}// 创建 JPEG 图像文件jpgFile, err := os.Create("./out/pic3.jpg")if err != nil {panic(err)}defer jpgFile.Close()// 使用 image/jpeg 包来编码 JPEG 图像buf := new(bytes.Buffer)if err := jpeg.Encode(buf, rgbaImg, &jpeg.Options{Quality: 80}); err != nil {panic(err)}_, err = jpgFile.Write(buf.Bytes())if err != nil {panic(err)}
}

在这里插入图片描述


http://www.ppmy.cn/news/955190.html

相关文章

ChatGPT4.0在投资中的运用初探

导读&#xff1a; ChatGPT自2022年11月30日发布以来&#xff0c;便受到金融行业越来越多的关注。如多家银行宣布成为文心一言首批生态合作伙伴&#xff0c;积极考虑将类ChatGPT为代表的生成式对话产品引入银行业务。 关注公众号&#xff1a;【互联互通社区】&#xff0c;回复【…

朗润国际期货招商:有人认为Bard智能水平不如 ChatGPT

&#xff08;2月8日&#xff09;美股开盘&#xff0c;谷歌大跌超7%&#xff0c;市值蒸发约1020亿美元。业内人士普遍认为&#xff0c;主要导火索是谷歌人工智能聊天机器人Bard在一场发布会上对用户提出的问题给出了错误答案。 Bard在回答“詹姆斯韦伯太空望远镜&#xff08;JW…

【ChatGPT】GPT-3.5+ChatGPT:图解概述

总结常见问题 –ChatGPT的受欢迎程度–ChatGPT的成本–ChatGPT的成就–在本地运行ChatGPT–API时间线GPT-3概述&#xff08;2020年5月&#xff09;GPT-3.5或InstructGPT概述&#xff08;2022年1月&#xff09;ChatGPT概述&#xff08;2022年11月&#xff09;ChatGPT的推荐替代方…

宝塔+x-ui面板共存,并使用Cloudflare WARP一键脚本解决openai 1020错误代码的问题记录

本文是根据网络上的资料后自行组合整理&#xff0c; 网站面板下载地址&#xff1a;宝塔 x-ui面板项目地址&#xff1a; x-ui Cloudflare WARP一键脚本项目地址&#xff1a; Cloudflare WARP 服务器版本&#xff1a;Ubuntu 22.04 x64 域名托管&#xff1a;cloudflare 宝塔安装 …

chatgpt-最常报错Access denied

一、问题 Access denied 的原因基本都是由于 IP 地址&#xff0c;例如我们用国内网络直接访问 ChatGPT 官网就会报错 Access denied&#xff08;访问被拒绝&#xff09;&#xff0c;Error reference number 1020&#xff08;错误参考编号&#xff1a;1020&#xff09; 二、原因…

爆火的 ChatGPT 太强了!写代码、改 bug,网友:可取代 Stack Overflow 了

OpenAI 新上线的 ChatGPT 可谓是火爆出圈&#xff0c;这个对话模型可以回答后续问题&#xff0c;承认错误&#xff0c;挑战不正确的前提&#xff0c;还能帮你修改代码中的 bug…… 只要和它聊上几句&#xff0c;一会儿功夫它就能把问题给你解决了。例如用户要求&#xff1a;「C…

PMP考题练习2023-07-19

1、敏捷管理专业人士注意到产品待办事项上一个新故事很模糊&#xff0c;缺少验收标准。敏捷管理专业人士应在sprint周期中的哪个时间点要求产品负责人提供更多详情&#xff1f; A.在待办事项梳理会上。 B.在sprint回顾会议上。 C.在每日scrum期问。 D.在选代评审会上。 选A 解释…

VPS(Linux)解决ChatGPT Access Denied(错误码1020)方法

本文参考了GitHub的一个开源项目&#xff0c;项目地址:https://github.com/fscarmen/warp 操作方法: 以下两个脚本二选一&#xff0c;部署完成后记得重启VPS VPS嵌套WARP后&#xff0c;建议开启BBR&#xff0c;能够有效降低延迟 WARP部署脚本: wget -N https://raw.githubu…