-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
330 lines (292 loc) · 10.2 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// https://github.com/leixiaohua1020/simplest_ffmpeg_device/blob/master/simplest_ffmpeg_grabdesktop/simplest_ffmpeg_grabdesktop.cpp
package main
import (
"fmt"
"os"
"time"
"unsafe"
"github.com/moonfdd/ffmpeg-go/ffcommon"
"github.com/moonfdd/ffmpeg-go/libavcodec"
"github.com/moonfdd/ffmpeg-go/libavdevice"
"github.com/moonfdd/ffmpeg-go/libavformat"
"github.com/moonfdd/ffmpeg-go/libavutil"
"github.com/moonfdd/ffmpeg-go/libswscale"
sdl "github.com/moonfdd/sdl2-go/sdl2"
"github.com/moonfdd/sdl2-go/sdlcommon"
)
// Output YUV420P
const OUTPUT_YUV420P = 0
// '1' Use Dshow
// '0' Use GDIgrab
const USE_DSHOW = 0
// Refresh Event
const SFM_REFRESH_EVENT = (sdl.SDL_USEREVENT + 1)
const SFM_BREAK_EVENT = (sdl.SDL_USEREVENT + 2)
var thread_exit ffcommon.FInt = 0
var ispush = true
func sfp_refresh_thread(opaque ffcommon.FVoidP) uintptr {
// thread_exit = 0
for thread_exit == 0 {
var event sdl.SDL_Event
event.Type = SFM_REFRESH_EVENT
if ispush {
event.SDL_PushEvent()
ispush = false
}
// sdl.SDL_Delay(40)
}
fmt.Println("sfp_refresh_thread 发送退出事件")
// thread_exit = 0
//Break
var event sdl.SDL_Event
event.Type = SFM_BREAK_EVENT
event.SDL_PushEvent()
return 0
}
// Show Dshow Device
func show_dshow_device() {
pFormatCtx := libavformat.AvformatAllocContext()
var options *libavutil.AVDictionary
libavutil.AvDictSet(&options, "list_devices", "true", 0)
iformat := libavformat.AvFindInputFormat("dshow")
fmt.Printf("========Device Info=============\n")
libavformat.AvformatOpenInput(&pFormatCtx, "video=dummy", iformat, &options)
fmt.Printf("================================\n")
}
// Show AVFoundation Device
func show_avfoundation_device() {
pFormatCtx := libavformat.AvformatAllocContext()
var options *libavutil.AVDictionary
libavutil.AvDictSet(&options, "list_devices", "true", 0)
iformat := libavformat.AvFindInputFormat("avfoundation")
fmt.Printf("==AVFoundation Device Info===\n")
libavformat.AvformatOpenInput(&pFormatCtx, "", iformat, &options)
fmt.Printf("=============================\n")
}
func main0() (ret ffcommon.FInt) {
var pFormatCtx *libavformat.AVFormatContext
var i, videoindex ffcommon.FInt
var pCodecCtx *libavcodec.AVCodecContext
var pCodec *libavcodec.AVCodec
var ifmt *libavformat.AVInputFormat
libavformat.AvRegisterAll()
libavformat.AvformatNetworkInit()
pFormatCtx = libavformat.AvformatAllocContext()
//Open File
//char filepath[]="src01_480x272_22.h265";
//avformat_open_input(&pFormatCtx,filepath,NULL,NULL)
//Register Device
libavdevice.AvdeviceRegisterAll()
//Windows
if USE_DSHOW != 0 {
//Use dshow
//
//Need to Install screen-capture-recorder
//screen-capture-recorder
//Website: http://sourceforge.net/projects/screencapturer/
//
ifmt = libavformat.AvFindInputFormat("dshow")
if libavformat.AvformatOpenInput(&pFormatCtx, "video=screen-capture-recorder", ifmt, nil) != 0 {
fmt.Printf("Couldn't open input stream1.\n")
return -1
}
} else {
//Use gdigrab
var options *libavutil.AVDictionary
//Set some options
//grabbing frame rate
//av_dict_set(&options,"framerate","5",0);
//The distance from the left edge of the screen or desktop
//av_dict_set(&options,"offset_x","20",0);
//The distance from the top edge of the screen or desktop
//av_dict_set(&options,"offset_y","40",0);
//Video frame size. The default is to capture the full screen
//av_dict_set(&options,"video_size","640x480",0);
// libavutil.AvDictSet(&options, "probesize", "100000000", 0)
ifmt = libavformat.AvFindInputFormat("gdigrab")
if libavformat.AvformatOpenInput(&pFormatCtx, "desktop", ifmt, &options) != 0 {
fmt.Printf("Couldn't open input stream2.\n")
return -1
}
}
if pFormatCtx.AvformatFindStreamInfo(nil) < 0 {
fmt.Println("Couldn't find stream information.")
return -1
}
videoindex = -1
for i = 0; i < int32(pFormatCtx.NbStreams); i++ {
if pFormatCtx.GetStream(uint32(i)).Codec.CodecType == libavutil.AVMEDIA_TYPE_VIDEO {
videoindex = i
break
}
}
if videoindex == -1 {
fmt.Printf("Didn't find a video stream.\n")
return -1
}
pCodecCtx = pFormatCtx.GetStream(uint32(videoindex)).Codec
pCodec = libavcodec.AvcodecFindDecoder(pCodecCtx.CodecId)
if pCodec == nil {
fmt.Printf("Codec not found.\n")
return -1
}
if pCodecCtx.AvcodecOpen2(pCodec, nil) < 0 {
fmt.Printf("Could not open codec.\n")
return -1
}
var pFrame, pFrameYUV *libavutil.AVFrame
pFrame = libavutil.AvFrameAlloc()
pFrameYUV = libavutil.AvFrameAlloc()
//unsigned char *out_buffer=(unsigned char *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
//avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
out_buffer := (*byte)(unsafe.Pointer(libavutil.AvMalloc(uint64(libavcodec.AvpictureGetSize(libavutil.AV_PIX_FMT_YUV420P, pCodecCtx.Width, pCodecCtx.Height)))))
((*libavcodec.AVPicture)(unsafe.Pointer(pFrameYUV))).AvpictureFill(out_buffer, libavutil.AV_PIX_FMT_YUV420P, pCodecCtx.Width, pCodecCtx.Height)
//SDL----------------------------
// if sdl.SDL_Init(sdl.SDL_INIT_VIDEO|sdl.SDL_INIT_AUDIO|sdl.SDL_INIT_TIMER) != 0 {
if sdl.SDL_Init(sdl.SDL_INIT_VIDEO) != 0 {
fmt.Printf("Could not initialize SDL - %s\n", sdl.SDL_GetError())
return -1
}
var screen_w, screen_h ffcommon.FInt = 640, 360
var mode *sdl.SDL_DisplayMode = new(sdl.SDL_DisplayMode)
if sdl.SDL_GetCurrentDisplayMode(0, mode) != 0 {
fmt.Printf("SDL: could not get current display mode - exiting:%s\n", sdl.SDL_GetError())
return -1
}
//Half of the Desktop's width and height.
screen_w = mode.W / 2
screen_h = mode.H / 2
window := sdl.SDL_CreateWindow("Simplest FFmpeg Grab Desktop", sdl.SDL_WINDOWPOS_UNDEFINED, sdl.SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, 0)
if window == nil {
fmt.Printf("SDL: could not create window - exiting:%s\n", sdl.SDL_GetError())
return -1
}
defer window.SDL_DestroyWindow()
renderer := window.SDL_CreateRenderer(-1, 0)
if renderer == nil {
fmt.Printf("SDL: could not create renderer - exiting:%s\n", sdl.SDL_GetError())
return -1
}
defer renderer.SDL_DestroyRenderer()
texture := renderer.SDL_CreateTexture(sdl.SDL_PIXELFORMAT_YV12,
sdl.SDL_TEXTUREACCESS_STREAMING,
pCodecCtx.Width,
pCodecCtx.Height)
defer texture.SDL_DestroyTexture()
window.SDL_ShowWindow()
time.Sleep(2 * time.Second)
var rect sdl.SDL_Rect
rect.X = 0
rect.Y = 0
rect.W = screen_w
rect.H = screen_h
var rect2 sdl.SDL_Rect
rect2.X = 0
rect2.Y = 0
rect2.W = mode.W
rect2.H = mode.H
//SDL End------------------------
// var got_picture ffcommon.FInt
//AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));
packet := &libavcodec.AVPacket{}
var fp_yuv *os.File
if OUTPUT_YUV420P != 0 {
fp_yuv, _ = os.Create("output.yuv")
}
var img_convert_ctx *libswscale.SwsContext
img_convert_ctx = libswscale.SwsGetContext(pCodecCtx.Width, pCodecCtx.Height, pCodecCtx.PixFmt, pCodecCtx.Width, pCodecCtx.Height, libavutil.AV_PIX_FMT_YUV420P, libswscale.SWS_BICUBIC, nil, nil, nil)
//------------------------------
//video_tid := sdl.SDL_CreateThread(sfp_refresh_thread, nil)
//
go sfp_refresh_thread(uintptr(0))
//sdl.SDL_CreateThread(sfp_refresh_thread, "", uintptr(0))
//Event Loop
var event sdl.SDL_Event
for {
//Wait
ispush = true
event.SDL_WaitEvent()
if event.Type == SFM_REFRESH_EVENT {
//------------------------------
if pFormatCtx.AvReadFrame(packet) >= 0 {
if int32(packet.StreamIndex) == videoindex {
if pCodecCtx.AvcodecSendPacket(packet) < 0 {
packet.AvPacketUnref()
continue
}
ret = pCodecCtx.AvcodecReceiveFrame(pFrame)
if ret < 0 {
fmt.Printf("Decode Error.\n")
return -1
}
if ret >= 0 {
// if got_picture != 0 {
img_convert_ctx.SwsScale((**byte)(unsafe.Pointer(&pFrame.Data)), (*int32)(unsafe.Pointer(&pFrame.Linesize)), 0, uint32(pCodecCtx.Height), (**byte)(unsafe.Pointer(&pFrameYUV.Data)), (*int32)(unsafe.Pointer(&pFrameYUV.Linesize)))
if OUTPUT_YUV420P != 0 {
y_size := pCodecCtx.Width * pCodecCtx.Height
fp_yuv.Write(ffcommon.ByteSliceFromByteP(pFrameYUV.Data[0], int(y_size))) //Y
fp_yuv.Write(ffcommon.ByteSliceFromByteP(pFrameYUV.Data[1], int(y_size)/4)) //U
fp_yuv.Write(ffcommon.ByteSliceFromByteP(pFrameYUV.Data[2], int(y_size)/4)) //V
}
texture.SDL_UpdateYUVTexture(&rect2,
pFrameYUV.Data[0], pFrameYUV.Linesize[0],
pFrameYUV.Data[1], pFrameYUV.Linesize[1],
pFrameYUV.Data[2], pFrameYUV.Linesize[2])
renderer.SDL_RenderClear()
renderer.SDL_RenderCopy(texture, nil, &rect)
renderer.SDL_RenderPresent()
}
}
packet.AvPacketUnref()
} else {
//Exit Thread
thread_exit = 1
fmt.Println("main 准备退出 1")
}
} else if event.Type == sdl.SDL_QUIT {
thread_exit = 1
fmt.Println("main 准备退出 2")
} else if event.Type == SFM_BREAK_EVENT {
fmt.Println("退出循环 3")
break
}
}
img_convert_ctx.SwsFreeContext()
if OUTPUT_YUV420P != 0 {
fp_yuv.Close()
}
sdl.SDL_Quit()
libavutil.AvFree(uintptr(unsafe.Pointer(out_buffer)))
libavutil.AvFree(uintptr(unsafe.Pointer(pFrame)))
libavutil.AvFree(uintptr(unsafe.Pointer(pFrameYUV)))
pCodecCtx.AvcodecClose()
libavformat.AvformatCloseInput(&pFormatCtx)
return 0
}
func main() {
os.Setenv("Path", os.Getenv("Path")+";./lib/windows/ffmpeg")
ffcommon.SetAvutilPath("./lib/windows/ffmpeg/avutil-56.dll")
ffcommon.SetAvcodecPath("./lib/windows/ffmpeg/avcodec-58.dll")
ffcommon.SetAvdevicePath("./lib/windows/ffmpeg/avdevice-58.dll")
ffcommon.SetAvfilterPath("./lib/windows/ffmpeg/avfilter-56.dll")
ffcommon.SetAvformatPath("./lib/windows/ffmpeg/avformat-58.dll")
ffcommon.SetAvpostprocPath("./lib/windows/ffmpeg/postproc-55.dll")
ffcommon.SetAvswresamplePath("./lib/windows/ffmpeg/swresample-3.dll")
ffcommon.SetAvswscalePath("./lib/windows/ffmpeg/swscale-5.dll")
sdlcommon.SetSDL2Path("./lib/windows/sdl/SDL2.0.16.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()
}