Files
go-rtsp/decoder.go
2021-07-22 15:25:07 +03:00

168 lines
4.5 KiB
Go

package rtsp
/*
#cgo LDFLAGS: -lavformat -lavutil -lavcodec
#include "ffmpeg.h"
*/
import "C"
import (
"fmt"
"unsafe"
)
type decoder struct {
index int
codecCtx *C.AVCodecContext
codec *C.AVCodec
swrContext *C.SwrContext
codecType int
}
func (decoder *decoder) Decode(packet *C.AVPacket) (pkt *Packet, err error) {
pkt = &Packet{}
pkt.streamIndex = int(packet.stream_index)
pkt.codecType = decoder.codecType
switch decoder.codecType {
case int(C.AVMEDIA_TYPE_AUDIO):
case int(C.AVMEDIA_TYPE_VIDEO):
default:
// do nothing
return
}
cerr := C.avcodec_send_packet(decoder.codecCtx, packet)
if int(cerr) != 0 {
err = fmt.Errorf("ffmpeg: avcodec_send_packet failed: %d", 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: %d", cerr)
return
}
switch decoder.codecType {
case C.AVMEDIA_TYPE_VIDEO:
pkt.width = int(frame.width)
pkt.height = int(frame.height)
var encPacket C.AVPacket
defer C.av_packet_unref(&encPacket)
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: %d", 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: %d", cerr)
return
}
}
pkt.data = make([]byte, int(encPacket.size))
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
case C.AVMEDIA_TYPE_AUDIO:
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:
if decoder.swrContext == nil {
layout := uint64(frame.channel_layout)
decoder.swrContext = C.swr_alloc_set_opts(nil, // we're allocating a new context
C.long(layout), // out_ch_layout
C.AV_SAMPLE_FMT_S16, // out_sample_fmt
frame.sample_rate, // out_sample_rate
C.long(layout), // in_ch_layout
decoder.codecCtx.sample_fmt, // in_sample_fmt
frame.sample_rate, // in_sample_rate
0, // log_offset
nil) // log_ctx
if cerr = C.swr_init(decoder.swrContext); cerr < C.int(0) {
decoder.swrContext = nil
err = fmt.Errorf("ffmpeg: swr_init failed: %d", cerr)
return
}
}
var encPacket C.AVPacket
defer C.av_packet_unref(&encPacket)
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: %d", cerr)
return
}
pkt.data = make([]byte, int(encPacket.size))
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
case C.AV_SAMPLE_FMT_S16:
var encPacket C.AVPacket
defer C.av_packet_unref(&encPacket)
if cerr = C.rtsp_avcodec_encode_wav(decoder.codecCtx, frame, &encPacket); cerr != C.int(0) {
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_wav failed: %d", cerr)
return
}
pkt.data = make([]byte, int(encPacket.size))
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
case C.AV_SAMPLE_FMT_S32:
if decoder.swrContext == nil {
layout := uint64(frame.channel_layout)
decoder.swrContext = C.swr_alloc_set_opts(nil, // we're allocating a new context
C.long(layout), // out_ch_layout
C.AV_SAMPLE_FMT_S16, // out_sample_fmt
frame.sample_rate, // out_sample_rate
C.long(layout), // in_ch_layout
decoder.codecCtx.sample_fmt, // in_sample_fmt
frame.sample_rate, // in_sample_rate
0, // log_offset
nil) // log_ctx
if cerr = C.swr_init(decoder.swrContext); cerr < C.int(0) {
decoder.swrContext = nil
err = fmt.Errorf("ffmpeg: swr_init failed: %d", cerr)
return
}
}
var encPacket C.AVPacket
defer C.av_packet_unref(&encPacket)
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: %d", cerr)
return
}
pkt.data = make([]byte, int(encPacket.size))
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
default:
err = fmt.Errorf("ffmpeg: audio format %d not supported: %d", frame.format)
return
}
default:
}
return
}