-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathdecoder.go
150 lines (126 loc) · 4 KB
/
decoder.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
package rtsp
/*
#cgo LDFLAGS: -lavformat -lavutil -lavcodec
#include "ffmpeg.h"
*/
import "C"
import (
"fmt"
"runtime"
"unsafe"
)
type decoder struct {
index int
codecCtx *C.AVCodecContext
codec *C.AVCodec
swrContext *C.SwrContext
codecType int
}
func decodeAVPacket(packet *C.AVPacket) (data []byte) {
data = make([]byte, int(packet.size))
copy(data, *(*[]byte)(unsafe.Pointer(&packet.data)))
return
}
func newDecoder(cstream *C.AVStream) (*decoder, error) {
decoder := &decoder{index: int(cstream.index)}
runtime.SetFinalizer(decoder, freeDecoder)
decoder.swrContext = nil
decoder.codecCtx = C.avcodec_alloc_context3(nil)
C.avcodec_parameters_to_context(decoder.codecCtx, cstream.codecpar)
decoder.codec = C.avcodec_find_decoder(decoder.codecCtx.codec_id)
decoder.codecType = int(cstream.codecpar.codec_type)
if decoder.codec == nil {
return nil, fmt.Errorf("ffmpeg: avcodec_find_decoder failed: codec %d not found", decoder.codecCtx.codec_id)
}
if cerr := C.avcodec_open2(decoder.codecCtx, decoder.codec, nil); int(cerr) != 0 {
return nil, fmt.Errorf("ffmpeg: avcodec_open2 failed: %s", CErr2Str(cerr))
}
return decoder, nil
}
func freeDecoder(decoder *decoder) {
if decoder.codecCtx != nil {
C.avcodec_close(decoder.codecCtx)
C.av_free(unsafe.Pointer(decoder.codecCtx))
decoder.codecCtx = nil
}
if decoder.codec != nil {
decoder.codec = nil
}
if decoder.swrContext != nil {
C.swr_close(decoder.swrContext)
C.swr_free(&decoder.swrContext)
}
}
func (decoder *decoder) decode(packet *C.AVPacket) (pkt *Packet, err error) {
pkt = &Packet{
streamIndex: int(packet.stream_index),
codecType: decoder.codecType,
}
if !pkt.IsAudio() && !pkt.IsVideo() {
// do nothing
return
}
cerr := C.avcodec_send_packet(decoder.codecCtx, packet)
if int(cerr) != 0 {
err = fmt.Errorf("ffmpeg: avcodec_send_packet failed: %s", CErr2Str(cerr))
return
}
frame := C.av_frame_alloc()
defer C.av_frame_free(&frame)
cerr = C.avcodec_receive_frame(decoder.codecCtx, frame)
if int(cerr) < 0 {
err = fmt.Errorf("ffmpeg: avcodec_receive_frame failed: %s", CErr2Str(cerr))
return
}
pkt.duration = int64(frame.pkt_duration)
pkt.position = int64(frame.pkt_pos)
var encPacket C.AVPacket
defer C.av_packet_unref(&encPacket)
switch {
case pkt.IsVideo():
pkt.width = int(frame.width)
pkt.height = int(frame.height)
pkt.keyFrame = int(frame.key_frame) == 1
switch frame.format {
case C.AV_PIX_FMT_NONE, C.AV_PIX_FMT_YUVJ420P:
if cerr = C.rtsp_avcodec_encode_jpeg(decoder.codecCtx, frame, &encPacket); cerr != C.int(0) {
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_jpeg failed: %s", CErr2Str(cerr))
return
}
default:
if cerr = C.rtsp_avcodec_encode_jpeg_nv12(decoder.codecCtx, frame, &encPacket); cerr != C.int(0) {
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_jpeg_nv12 failed: %s", CErr2Str(cerr))
return
}
}
case pkt.IsAudio():
pkt.bitRate = int(decoder.codecCtx.bit_rate)
pkt.sampleRate = int(frame.sample_rate)
pkt.channels = int(frame.channels)
switch frame.format {
case C.AV_SAMPLE_FMT_FLTP, C.AV_SAMPLE_FMT_S32:
if decoder.swrContext == nil {
decoder.swrContext = swrAllocSetOpts(uint64(frame.channel_layout), frame.sample_rate, decoder.codecCtx.sample_fmt)
if cerr = C.swr_init(decoder.swrContext); cerr < C.int(0) {
decoder.swrContext = nil
err = fmt.Errorf("ffmpeg: swr_init failed: %s", CErr2Str(cerr))
return
}
}
if cerr = C.rtsp_avcodec_encode_resample_wav(decoder.codecCtx, decoder.swrContext, frame, &encPacket); cerr < C.int(0) {
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_resample_wav failed: %s", CErr2Str(cerr))
return
}
case C.AV_SAMPLE_FMT_S16:
if cerr = C.rtsp_avcodec_encode_wav(decoder.codecCtx, frame, &encPacket); cerr != C.int(0) {
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_wav failed: %s", CErr2Str(cerr))
return
}
default:
err = fmt.Errorf("ffmpeg: audio format %d not supported", frame.format)
return
}
}
pkt.data = decodeAVPacket(&encPacket)
return
}