2026-08-13 11:28:40 +08:00
/*
* Buffered I/O for ffmpeg system
* Copyright (c) 2000,2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* LOOPBUF READ
* Write By zhi.zhou@amlogic.com
*
*/
#include "libavutil/crc.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "avio.h"
#include <stdarg.h>
#include "aviolpcache.h"
#include "aviolpbuf.h"
//#include "amconfigutils.h"
//#include "../udrm/udrm.h"
/*
Pos
buffer rp wp buffer_end
| | | |
================================
| |
|<--------------buffer_size-------------->|
valid_data_too_read:
if wp >= rp
wp-rp
else
buffer_size-(rp-wp)
valid_data_size:for seek;
alway ++,utill seek to empte the buff;
Can seek back size:
min(valid_data_size-valid_data_too_read,data between buffe,rp)
*/
//#define LP_BUFFER_DEBUG
#define LP_SK_DEBUG
//#define LP_RD_DEBUG
#define lp_print(level, fmt...) av_log(NULL, level, ##fmt)
#ifdef LP_SK_DEBUG
#define lp_sprint(level, fmt...) av_log(NULL, level, ##fmt)
#else
#define lp_sprint(level, fmt...)
#endif
#ifdef LP_RD_DEBUG
#define lp_rprint(level, fmt...) av_log(NULL, level, ##fmt)
#else
#define lp_rprint(level, fmt...)
#endif
#ifdef LP_BUFFER_DEBUG
#define lp_bprint(level, fmt...) av_log(NULL, level, ##fmt)
#else
#define lp_bprint(level, fmt...)
#endif
#define LP_ASSERT(x) \
do \
{ \
if (!(x)) \
av_log(NULL, AV_LOG_INFO, "****\t\tERROR at line file%s=%d\n\n\n", __FILE__, __LINE__); \
} while (0)
#define DEF_MAX_READ_SEEK (1024 * 1024 * 3)
#define MAX_DECRYPT_DATA_LEN (20 * 188)
int url_lpopen ( URLContext * s , int size )
{
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpopen=%d \n " , __FUNCTION__ , __LINE__ , size );
url_lpbuf_t * lp ;
int blocksize = 32 * 1024 ;
int ret ;
float value = 0.0 ;
int bufsize = 0 ;
if ( size == 0 )
{
ret = 0 ; //am_getconfig_float("libplayer.ffmpeg.lpbufsizemax", &value);
if ( ret < 0 || value < 1024 * 32 )
{
if ( 0 ) //(am_getconfig_bool_def("media.amplayer.low_ram", 0))
{
size = IO_LP_BUFFER_SIZE / 8 ;
}
else
{
size = IO_LP_BUFFER_SIZE ;
}
}
else
{
size = ( int ) value ;
}
}
lp_bprint ( AV_LOG_INFO , "url_lpopen=%d \n " , size );
if ( ! s )
return - 1 ;
lp_bprint ( AV_LOG_INFO , "url_lpopen2=%d \n " , size );
ret = 0 ; //am_getconfig_float("libplayer.ffmpeg.lpbufblocksize", &value);
if ( ret >= 0 && value >= 32 )
{
blocksize = ( int ) value ;
}
lp_sprint ( AV_LOG_INFO , "lpbuffer block size=%d \n " , blocksize );
lp = av_mallocz ( sizeof ( url_lpbuf_t ));
if ( ! lp )
return AVERROR ( ENOMEM );
lp -> buffer = av_malloc ( size );
if ( ! lp -> buffer )
{
unsigned int failedsize = size / 2 ; /*if no memory used 1/2 size */
ret = 0 ; //am_getconfig_float("libplayer.ffmpeg.lpbuffaildsize", &value);
if ( ret >= 0 && value >= 1024 )
{
failedsize = ( unsigned int ) value ;
}
lp_sprint ( AV_LOG_INFO , "malloc buf failed,used failed size=%d \n " , failedsize );
lp -> buffer = av_malloc ( failedsize );
while ( ! lp -> buffer )
{
failedsize = failedsize / 2 ;
if ( failedsize < 16 * 1024 )
{ /*do't malloc too small size failed size*/
av_free ( lp );
return AVERROR ( ENOMEM );
}
lp -> buffer = av_malloc ( failedsize );
}
bufsize = failedsize ;
}
else
{
bufsize = size ;
}
lp_sprint ( AV_LOG_INFO , "url_lpopen used lp buf size=%d \n " , bufsize );
s -> lpbuf = lp ;
lp -> buffer_size = bufsize ;
lp -> rp = lp -> buffer ;
lp -> wp = lp -> buffer ;
lp -> buffer_end = lp -> buffer + bufsize ;
lp -> valid_data_size = 0 ;
lp -> pos = 0 ;
lp -> block_read_size = FFMIN ( blocksize , bufsize >> 4 );
lp_lock_init ( & lp -> mutex , NULL );
lp -> file_size = url_lpseek ( s , 0 , AVSEEK_SIZE );
lp -> cache_enable = 0 ;
lp -> cache_id = aviolp_cache_open ( s -> filename , url_lpseek ( s , 0 , AVSEEK_SIZE ));
lp -> dbg_cnt = 0 ;
ret = 0 ; //am_getconfig_float("libplayer.ffmpeg.lpbufmaxbuflv", &value);
if ( ret < 0 )
lp -> max_forword_level = 1 ;
else
{
lp -> max_forword_level = value ;
}
if ( lp -> cache_id != 0 )
lp -> cache_enable = 1 ;
lp_bprint ( AV_LOG_INFO , "url_lpopen4%d \n " , bufsize );
ret = 0 ; //am_getconfig_float("libplayer.ffmpeg.maxreadseek", &value);
if ( ret >= 0 && value >= 0 )
{
lp -> max_read_seek = value ;
}
else
{
lp -> max_read_seek = DEF_MAX_READ_SEEK ;
}
lp -> drm_ts_flags = 0 ;
lp -> decrypt_data = NULL ;
lp -> decrypt_data_len = 0 ;
lp -> decrypt_read_len = 0 ;
lp -> need_find_ts_start_pos = 1 ;
lp -> ts_tail_len = 0 ;
lp -> ts_tail_pos = 0 ;
lp -> drm_handle = 0 ;
lp -> fp1 = NULL ;
lp -> fp2 = NULL ;
return 0 ;
}
#if 0
int url_lpopen_ex(URLContext *s,
int size,
int flags,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int64_t (*seek)(void *opaque, int64_t offset, int whence))
{
int ret;
URLContext *uc=s;
uc->av_class = NULL;
uc->filename = (char *)NULL;
uc->prot =uc+ sizeof(URLContext) ;
uc->flags = flags;
uc->is_streamed = 0; /* default = not streamed */
uc->max_packet_size = 0; /* default: stream file */
ret=url_lpopen(uc,size);
if (ret == 0) {
uc->prot->url_read=read_packet;
uc->prot->url_seek=seek;
uc->prot->url_exseek=seek;
uc->prot->flags=uc->flags ;
}else{
}
return ret;
}
#endif
static int url_ts_probe ( unsigned char * data , int len )
{
unsigned char * buf = data ;
unsigned char scan_num = 188 ;
do
{
if (( len - 188 + scan_num ) > 188 * 3 && buf [ 0 ] == 0x47 && buf [ 188 ] == 0x47 && buf [ 188 * 2 ] == 0x47 )
return 188 - scan_num ; //ts format
scan_num -- ;
buf ++ ;
} while ( scan_num > 0 );
return - 1 ; //other format
}
int url_lpopen_ex ( URLContext * s ,
int size ,
int flags ,
int ( * read_packet )( void * opaque , uint8_t * buf , int buf_size ),
int64_t ( * seek )( void * opaque , int64_t offset , int whence ))
{
int ret ;
URLContext * uc = s ;
if ( ! uc -> prot )
{
lp_print ( AV_LOG_INFO , "url_lpopen_ex failed \n " );
return - 1 ;
}
uc -> av_class = NULL ;
uc -> filename = ( char * ) NULL ;
uc -> flags = flags ;
uc -> is_streamed = 0 ; /* default = not streamed */
uc -> max_packet_size = 0 ; /* default: stream file */
// uc->UrlCtx.prot->url_read = read_packet;
// uc->UrlCtx.prot->url_seek = seek;
// uc->UrlCtx.prot->url_exseek = seek;
// uc->UrlCtx.prot->flags = uc->UrlCtx.flags;
ret = url_lpopen ( uc , size );
if ( ret < 0 )
{
lp_print ( AV_LOG_INFO , " url_lpopen -failed \n " );
return - 1 ;
}
return ret ;
}
int url_lpfillbuffer ( URLContext * s , int size )
{
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],size:%d,s->priv_data:%d" , __FUNCTION__ , __LINE__ , size , s -> priv_data );
url_lpbuf_t * lp ;
int rlen = 0 ;
int ssread ;
int cache_read_len = 0 ;
int64_t tmprp ;
if ( ! s || ! s -> lpbuf )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
lp_lock ( & lp -> mutex );
if ( lp -> wp >= lp -> rp )
{
if ( lp -> rp != lp -> buffer )
ssread = FFMIN ( size , lp -> buffer_end - lp -> wp );
else
ssread = FFMIN ( size , lp -> buffer_end - lp -> wp - 32 );
}
else
ssread = FFMIN ( size , lp -> rp - lp -> wp - 32 ); /*reversed 32bytes;*/
if ( ssread <= 0 )
{
rlen = 0 ;
goto release ;
}
if ( lp -> cache_enable )
{
/*do read on cache first*/
rlen = aviolp_cache_read ( lp -> cache_id , lp -> pos , lp -> wp , ssread );
cache_read_len = rlen ;
}
if ( rlen <= 0 )
{
if ( lp -> file_size > 0 && lp -> pos >= lp -> file_size )
{
rlen = 0 ; /*file read end*/
goto release ;
}
else if ( lp -> cache_enable )
{
/*maybe do read from cache file before,so seek it now*/
int64_t lowlevelpos = s -> prot -> url_seek ( s , 0 , SEEK_CUR );
if ( lowlevelpos > 0 && lowlevelpos != lp -> pos )
{
int ret = s -> prot -> url_seek ( s , lp -> pos , SEEK_SET );
if ( ret != lp -> pos )
{
rlen = - 1 ; /*error*/
goto release ;
}
}
}
tmprp = lp -> pos ;
lp_unlock ( & lp -> mutex ); /*release lock for long time read*/
if ( lp -> drm_ts_flags && lp -> decrypt_data == NULL )
{
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpfillbuffer begin init drm------- \n " , __FUNCTION__ , __LINE__ );
lp -> decrypt_data = av_malloc ( MAX_DECRYPT_DATA_LEN );
if ( lp -> decrypt_data == NULL )
{
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpfillbuffer decrypt_data malloc failed!! \n " , __FUNCTION__ , __LINE__ );
lp -> drm_ts_flags = 0 ;
}
#if 0
else
{
//get decrypt handle
lp->drm_handle = udrm_decrypt_start(0);
if (lp->drm_handle == -1)
{
lp->drm_ts_flags = 0;
lp->drm_handle = 0;
lp_sprint(AV_LOG_ERROR, "url_lpfillbuffer udrm_decrypt_start error!!\n");
}
else
{
lp_sprint(AV_LOG_INFO, "url_lpfillbuffer drm_handle=0x%x-------\n", lp->drm_handle);
//clear lpbuf
lp->rp = lp->buffer;
lp->wp = lp->buffer;
lp->valid_data_size = 0;
lp->pos = 0;
if (0)//(am_getconfig_bool_def("libplayer.ts.udrm.dumpfile", 0))
{
lp->fp1 = fopen("/data/lp_recv.ts", "w");
if (lp->fp1 == NULL)
lp_sprint(AV_LOG_INFO, "url_lpfillbuffer open lp_recv.ts failed!\n");
lp->fp2 = fopen("/data/lp_descrypt.ts", "w");
if (lp->fp2 == NULL)
lp_sprint(AV_LOG_INFO, "url_lpfillbuffer open lp_descrypt.ts failed!\n");
}
}
}
#endif
}
if ( ! lp -> drm_ts_flags )
{
rlen = s -> prot -> url_read ( s , lp -> wp , ssread );
}
else
{
if ( lp -> decrypt_read_len == 0 && lp -> decrypt_data_len == 0 )
{
int read_len = 0 ;
if ( lp -> ts_tail_len > 0 )
{
//add ts tail
memcpy ( lp -> decrypt_data , lp -> decrypt_data + lp -> ts_tail_pos , lp -> ts_tail_len );
lp -> decrypt_data_len = lp -> ts_tail_len ;
lp -> ts_tail_len = 0 ;
lp -> ts_tail_pos = 0 ;
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpfillbuffer add ts_tail %d, [0]=0x%x \n " ,
__FUNCTION__ , __LINE__ , lp -> decrypt_data_len , lp -> decrypt_data [ 0 ]);
}
//download ts data
read_len = ( lp -> decrypt_data_len > 0 ) ? ( MAX_DECRYPT_DATA_LEN - lp -> decrypt_data_len ) : MAX_DECRYPT_DATA_LEN ;
rlen = s -> prot -> url_read ( s , lp -> decrypt_data + lp -> decrypt_data_len , read_len );
lp -> decrypt_data_len += ( rlen >= 0 ? rlen : 0 );
lp -> decrypt_read_len = 0 ;
//lp_sprint(AV_LOG_INFO, "url_lpfillbuffer url_read_len=%d, rlen=%d\n", read_len, rlen);
}
}
lp_lock ( & lp -> mutex );
if ( tmprp != lp -> pos )
rlen = AVERROR ( EAGAIN ); /*pos have changed,so I think we have a seek on read*/
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],filled buffer from remote=%d \n " , __FUNCTION__ , __LINE__ , rlen );
}
if ( lp -> drm_ts_flags )
{
if ( lp -> decrypt_read_len == 0 && lp -> decrypt_data_len > 0 )
{
int decrypt_len = 0 ;
//check ts tail
if ( lp -> decrypt_data_len % 188 != 0 && lp -> need_find_ts_start_pos == 0 )
{
lp -> ts_tail_len = lp -> decrypt_data_len % 188 ;
lp -> ts_tail_pos = lp -> decrypt_data_len - lp -> ts_tail_len ;
lp -> decrypt_data_len -= lp -> ts_tail_len ;
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpfillbuffer check tail_len=%d, [0]=0x%x \n " ,
__FUNCTION__ , __LINE__ , lp -> ts_tail_len , lp -> decrypt_data [ lp -> ts_tail_pos ]);
}
if ( lp -> decrypt_data_len > 0 && lp -> need_find_ts_start_pos == 1 )
{
//check ts start pos
int ts_start_pos = url_ts_probe ( lp -> decrypt_data , lp -> decrypt_data_len );
if ( ts_start_pos > 0 )
{
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpfillbuffer truncate_len=%d \n " , __FUNCTION__ , __LINE__ , ts_start_pos );
lp -> decrypt_data_len -= ts_start_pos ;
memcpy ( lp -> decrypt_data , lp -> decrypt_data + ts_start_pos , lp -> decrypt_data_len );
//rlen = s->prot->url_read(s, lp->decrypt_data+lp->decrypt_data_len, ts_start_pos);
//lp->decrypt_data_len += rlen;
//check ts tail
if ( lp -> decrypt_data_len % 188 != 0 )
{
lp -> ts_tail_len = lp -> decrypt_data_len % 188 ;
lp -> decrypt_data_len -= lp -> ts_tail_len ;
lp -> ts_tail_pos = lp -> decrypt_data_len ;
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpfillbuffer truncate tail_len=%d(%d),[0]=0x%x \n " , __FUNCTION__ , __LINE__ ,
lp -> ts_tail_len , lp -> decrypt_data_len + lp -> ts_tail_len , lp -> decrypt_data [ lp -> ts_tail_pos ]);
}
}
lp -> need_find_ts_start_pos = 0 ;
}
if ( lp -> decrypt_data_len > 0 )
{
//udrm decrypt
if ( lp -> fp1 )
fwrite ( lp -> decrypt_data , lp -> decrypt_data_len , 1 , lp -> fp1 );
#if 0
decrypt_len = udrm_ts_decrypt(lp->drm_handle,
lp->decrypt_data, lp->decrypt_data_len,
lp->decrypt_data, lp->decrypt_data_len);
//lp_sprint(AV_LOG_INFO, "url_lpfillbuffer decrypt_len = %d, [0]=0x%x %d\n",
// decrypt_len, lp->decrypt_data[0], lp->save_flag);
if (decrypt_len >= 0)
{
lp->decrypt_data_len = decrypt_len;
if (lp->fp2)
fwrite(lp->decrypt_data, decrypt_len, 1, lp->fp2);
}
#endif
//else
// lp_sprint(AV_LOG_ERROR, "url_lpfillbuffer udrm_ts_decrypt error!!\n");
}
}
else
{
rlen = 0 ;
}
if ( lp -> decrypt_data_len > 0 )
{
//fill decrypt_data to lpbuf
if ( lp -> wp >= lp -> rp )
ssread = FFMIN ( lp -> decrypt_data_len - lp -> decrypt_read_len , lp -> buffer_end - lp -> wp );
else
ssread = FFMIN ( lp -> decrypt_data_len - lp -> decrypt_read_len , lp -> rp - lp -> wp );
memcpy ( lp -> wp , lp -> decrypt_data + lp -> decrypt_read_len , ssread );
lp -> decrypt_read_len += ssread ;
if ( lp -> cache_enable && cache_read_len <= 0 ) /*not read from cache itself*/
aviolp_cache_write ( lp -> cache_id , lp -> pos , lp -> wp , ssread );
lp -> pos += ssread ;
lp -> wp += ssread ;
lp -> valid_data_size += ssread ;
if ( lp -> wp >= lp -> buffer_end )
{
lp -> wp = lp -> buffer ;
}
rlen = ssread ;
if ( lp -> decrypt_read_len >= lp -> decrypt_data_len )
lp -> decrypt_read_len = lp -> decrypt_data_len = 0 ;
//lp_sprint(AV_LOG_INFO, "url_lpfillbuffer fill_len = %d\n", ssread);
}
}
else if ( rlen > 0 )
{
if ( lp -> cache_enable && cache_read_len <= 0 ) /*not read from cache itself*/
aviolp_cache_write ( lp -> cache_id , lp -> pos , lp -> wp , rlen );
lp -> valid_data_size += rlen ;
lp -> pos += rlen ;
lp -> wp += rlen ;
if ( lp -> wp >= lp -> buffer_end )
lp -> wp = lp -> buffer ;
}
release :
lp_unlock ( & lp -> mutex );
return rlen ;
}
2026-08-25 10:02:36 +08:00
int url_lpread ( void * void_p , unsigned char * buf , int size )
2026-08-13 11:28:40 +08:00
{
url_lpbuf_t * lp ;
int len = size ;
int valid_data_can_read ;
2026-08-25 10:02:36 +08:00
URLContext * s = ( URLContext * ) void_p ;
2026-08-13 11:28:40 +08:00
unsigned char * tbuf = buf ;
if ( ! s || ! s -> lpbuf )
{
return - 1 ;
}
lp = s -> lpbuf ;
lp_lock ( & lp -> mutex );
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpread:buffer=%x,rp=%x,wp=%x,end=%x,lp->valid_data_size=%d,pos=%lld \n " , __FUNCTION__ , __LINE__ , lp -> buffer , lp -> rp , lp -> wp , lp -> buffer_end , lp -> valid_data_size , lp -> pos );
while ( len > 0 )
{
if ( lp -> wp >= lp -> rp )
valid_data_can_read = lp -> wp - lp -> rp ;
else
valid_data_can_read = lp -> buffer_end - lp -> rp ;
valid_data_can_read = FFMIN ( len , valid_data_can_read );
LP_ASSERT ( valid_data_can_read >= 0 );
if ( valid_data_can_read == 0 )
{
int rlen ;
lp_unlock ( & lp -> mutex );
if (( len < lp -> block_read_size ) && ( lp -> seekflags & LESS_BUFF_DATA ))
rlen = url_lpfillbuffer ( s , len );
else
rlen = url_lpfillbuffer ( s , lp -> block_read_size );
if ( rlen <= 0 )
{
//lp_unlock(&lp->mutex);
return (( size - len ) > 0 ) ? ( size - len ) : rlen ;
}
lp_lock ( & lp -> mutex );
}
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d],url_lpread:buffer=%x,rp=%x,wp=%x,end=%x,tbuf=%x,valid_data_can_read=%x(%d) \n " ,
__FUNCTION__ , __LINE__ , lp -> buffer , lp -> rp , lp -> wp , lp -> buffer_end , tbuf , valid_data_can_read , valid_data_can_read );
if ( valid_data_can_read > 0 )
{
if ( tbuf != NULL )
{
memcpy ( tbuf , lp -> rp , valid_data_can_read );
tbuf += valid_data_can_read ;
}
lp -> rp += valid_data_can_read ;
if ( lp -> rp >= lp -> buffer_end )
lp -> rp = lp -> buffer ;
len -= valid_data_can_read ;
}
LP_ASSERT ( lp -> rp >= lp -> buffer );
LP_ASSERT ( lp -> rp < lp -> buffer_end );
}
lp_unlock ( & lp -> mutex );
return ( size - len );
}
2026-08-25 10:02:36 +08:00
int64_t url_lpseek ( void * void_p , int64_t offset , int whence )
2026-08-13 11:28:40 +08:00
{
av_log ( NULL , AV_LOG_DEBUG , "[%s,%d] \n " , __FUNCTION__ , __LINE__ );
int64_t pos_on_read ;
url_lpbuf_t * lp ;
int valid_data_can_seek_forward ;
int valid_data_can_seek_back ;
2026-08-25 10:02:36 +08:00
URLContext * s = ( URLContext * ) void_p ;
2026-08-13 11:28:40 +08:00
int64_t offset1 ;
int ret ;
if ( ! s || ! s -> lpbuf )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
lp_lock ( & lp -> mutex );
lp_sprint ( AV_LOG_INFO , "url_lpseek:offset=%lld whence=%d,buffer=%x,rp=%x,wp=%x,end=%x,pos=%lld \n " ,
offset , whence , lp -> buffer , lp -> rp , lp -> wp , lp -> buffer_end , lp -> pos );
if ( whence == AVSEEK_SIZE )
{
int64_t size ;
if ( ! s -> prot -> url_seek )
{
lp_unlock ( & lp -> mutex );
return - 1 ;
}
size = s -> prot -> url_seek ( s , 0 , AVSEEK_SIZE );
if ( size < 0 && size != AVERROR_STREAM_SIZE_NOTVALID )
{
if (( size = s -> prot -> url_seek ( s , - 1 , SEEK_END )) < 0 )
{
lp_unlock ( & lp -> mutex );
return size ;
}
size ++ ;
s -> prot -> url_seek ( s , lp -> pos , SEEK_SET );
}
lp_sprint ( AV_LOG_INFO , "get file size=%lld \n " , size );
lp_unlock ( & lp -> mutex );
return size ;
}
else if ( whence == SEEK_END )
{
if ( ! s -> prot -> url_seek )
{
lp_unlock ( & lp -> mutex );
return - 1 ;
}
if (( offset1 = s -> prot -> url_seek ( s , offset , SEEK_END )) < 0 )
{
lp_unlock ( & lp -> mutex );
return offset1 ;
}
lp -> rp = lp -> buffer ;
lp -> wp = lp -> buffer ;
lp -> valid_data_size = 0 ;
lp -> pos = offset1 ;
lp -> decrypt_data_len = 0 ;
lp -> decrypt_read_len = 0 ;
lp -> ts_tail_len = 0 ;
lp -> ts_tail_pos = 0 ;
lp -> need_find_ts_start_pos = 1 ;
lp_unlock ( & lp -> mutex );
return offset1 ;
}
if ( whence != SEEK_CUR && whence != SEEK_SET )
{
lp_unlock ( & lp -> mutex );
return AVERROR ( EINVAL );
}
if ( lp -> wp >= lp -> rp )
valid_data_can_seek_forward = lp -> wp - lp -> rp ;
else
valid_data_can_seek_forward = lp -> buffer_size - ( lp -> rp - lp -> wp );
pos_on_read = lp -> pos - valid_data_can_seek_forward ;
if ( whence == SEEK_CUR )
{
offset1 = pos_on_read ;
if ( offset == 0 )
{
lp_unlock ( & lp -> mutex );
return offset1 ;
}
offset += offset1 ;
}
valid_data_can_seek_back = FFMIN ( lp -> valid_data_size - valid_data_can_seek_forward ,
lp -> buffer_size - valid_data_can_seek_forward - 64 );
if ( valid_data_can_seek_back < 0 )
valid_data_can_seek_back = 0 ;
offset1 = offset - pos_on_read ; /*seek forword or back*/
lp_sprint ( AV_LOG_INFO , "url_lpseek:pos_on_read=%lld,can seek forwart=%d,can seek bacd=%d,offset1=%lld \n " ,
pos_on_read , valid_data_can_seek_forward , valid_data_can_seek_back , offset1 );
if ( offset1 >= 0 && offset1 <= valid_data_can_seek_forward )
{ /*seek forward in lp buffer*/
lp_sprint ( AV_LOG_INFO , "url_lpseek:buffer seek forword offset=%lld offset1=%lld whence=%d \n " , offset , offset1 , whence );
lp -> rp += ( int ) offset1 ;
if ( lp -> rp >= lp -> buffer_end )
lp -> rp -= lp -> buffer_size ;
}
else if ( offset1 < 0 && ( - offset1 ) <= valid_data_can_seek_back )
{ /*seek back in lp buffer*/
lp_sprint ( AV_LOG_INFO , "url_lpseek:buffer seek back offset=%lld offset1=%lld whence=%d,(int)offset1=%d \n " , offset , offset1 , whence , ( int ) offset1 );
lp -> rp += ( int ) offset1 ;
if ( lp -> rp < lp -> buffer )
lp -> rp += lp -> buffer_size ;
}
else if (( s -> is_streamed && offset1 > 0 ) || /*can't suport seek,and can support read seek.*/
(( offset1 > 0 && s -> is_slowmedia ) && /*is slowmedia and seek formard*/
( offset1 < lp -> buffer_size - lp -> block_read_size && offset1 <= (( lp -> seekflags & MORE_READ_SEEK ) ? lp -> max_read_seek * 4 : lp -> max_read_seek )) && /*don't do too big size seek*/
( lp -> file_size <= 0 || ( lp -> file_size > 0 && offset1 < ( 3 * lp -> file_size / 4 ))) && /*if offset1>filesize*3/4,thendo first seek end,don't buffer*/
( offset1 <= (( lp -> seekflags & LESS_READ_SEEK ) ? lp -> max_read_seek / 16 : (( lp -> seekflags & MORE_READ_SEEK ) ? lp -> max_read_seek * 4 : lp -> max_read_seek ))))) /*do less readseek,if have less seek flags*/
{ /*seek to buffer end,but buffer is not full,do read seek*/
int read_offset , ret ;
lp_sprint ( AV_LOG_INFO , "url_lpseek:buffer read seek forward offset=%lld offset1=%lld whence=%d \n " , offset , offset1 , whence );
lp -> rp += valid_data_can_seek_forward ;
if ( lp -> rp >= lp -> buffer_end )
lp -> rp -= lp -> buffer_size ;
lp_unlock ( & lp -> mutex );
read_offset = offset1 - valid_data_can_seek_forward ;
while ( read_offset > 0 )
{
ret = url_lpread ( s , NULL , read_offset ); /*do read seek*/
if ( ret > 0 )
read_offset -= ret ;
else if ( ret != AVERROR ( EAGAIN ))
{
offset = ret ; /*get error,exit now*/
break ;
}
}
lp_lock ( & lp -> mutex );
}
else
{ /*not support in buffer seek,do low level seek now*/
lp_sprint ( AV_LOG_INFO , "url_lpseek:buffer lowlevel seek offset=%lld offset1=%lld whence=%d \n " , offset , offset1 , whence );
if ( ! s -> prot -> url_seek )
{
lp_unlock ( & lp -> mutex );
return - 1 ;
}
if ( lp -> cache_enable && offset < lp -> file_size )
{
/*if cache enable not need to seek here,seek on cache missed*/
; /*do't do seek here*/
}
else if (( offset1 = s -> prot -> url_seek ( s , offset , SEEK_SET )) < 0 )
{
lp -> valid_data_size = 0 ; /*seek failed clear all old datas*/
#if 0
if ((s->seekflags & URL_SEEK_FAIL_NO_BACK) == 0)
offset1 = s->prot->url_seek(s, lp->pos, SEEK_SET);/*clear the lowlevel errors*/
#endif
lp_unlock ( & lp -> mutex );
return offset1 ;
}
lp -> rp = lp -> buffer ;
lp -> wp = lp -> buffer ;
lp -> valid_data_size = 0 ;
lp -> pos = offset ;
lp -> decrypt_data_len = 0 ;
lp -> decrypt_read_len = 0 ;
lp -> ts_tail_len = 0 ;
lp -> ts_tail_pos = 0 ;
lp -> need_find_ts_start_pos = 1 ;
}
lp_sprint ( AV_LOG_INFO , "url_lpseekend:offset=%lld whence=%d,buffer=%x,rp=%x,wp=%x,end=%x,pos=%lld \n " ,
offset , whence , lp -> buffer , lp -> rp , lp -> wp , lp -> buffer_end , lp -> pos );
LP_ASSERT ( lp -> rp >= lp -> buffer );
LP_ASSERT ( lp -> rp < lp -> buffer_end );
lp_unlock ( & lp -> mutex );
return offset ;
}
int64_t url_lpexseekoffset ( URLContext * s , int64_t offset )
{
int forward_data = 0 ;
int back_data = 0 ;
lp_print ( AV_LOG_INFO , "[%s:%d] doing url_lpexseekoffset \n " , __FUNCTION__ , __LINE__ );
int buffer_validdata_size = url_lp_getbuffering_size ( s , & forward_data , & back_data );
if ( buffer_validdata_size <= 0 )
{
lp_print ( AV_LOG_ERROR , "[%s:%d] LOOPBUFFER buffer is empty \n " , __FUNCTION__ , __LINE__ );
return - 1 ;
}
int64_t seek_time = 0 ;
#if 0
if ((seek_time = s->UrlCtx.prot->url_exseek(s, offset, AVSEEK_LOOPBUFFER_OFFSET)) < 0)
{
lp_print(AV_LOG_ERROR, "[%s:%d] LOOPBUFFER seek failed seek_time=%lld\n", __FUNCTION__, __LINE__, seek_time);
return -1;
}
#endif
int64_t seek_pos = 0 ;
if ( s -> priv_info > buffer_validdata_size )
{
lp_print ( AV_LOG_ERROR , "[%s:%d] LOOPBUFFER seek out of range \n " , __FUNCTION__ , __LINE__ );
return - 1 ;
}
else if ( s -> priv_info < 0 )
{
lp_print ( AV_LOG_ERROR , "[%s:%d] LOOPBUFFER seek error, maybe cached hls data is not continuous ! \n " , __FUNCTION__ , __LINE__ );
return - 1 ;
}
else
{
seek_pos = forward_data - s -> priv_info ;
}
if ( url_lpseek ( s , seek_pos , SEEK_CUR ) < 0 )
{
lp_print ( AV_LOG_ERROR , "[%s:%d] Failed to seek SEEK_CUR pos=%lld,time=%lld,forward_data=%d \n " ,
__FUNCTION__ , __LINE__ , seek_pos , seek_time , forward_data );
return - 1 ;
}
lp_print ( AV_LOG_INFO , "[%s:%d] seek SEEK_CUR pos=%lld,time=%lld,forward_data=%d \n " ,
__FUNCTION__ , __LINE__ , seek_pos , seek_time , forward_data );
return seek_time ;
}
int64_t url_lpexseek ( URLContext * s , int64_t offset , int whence )
{
url_lpbuf_t * lp ;
int64_t ret ;
if ( ! s || ! s -> lpbuf /*|| !s->UrlCtx.prot->url_exseek*/ )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
lp_lock ( & lp -> mutex );
if ( whence == AVSEEK_FULLTIME )
{
// ret = s->UrlCtx.prot->url_exseek(s, 0, AVSEEK_FULLTIME); /*clear the lowlevel errors*/
}
else if ( whence == AVSEEK_BUFFERED_TIME )
{
// ret = s->UrlCtx.prot->url_exseek(s, 0, AVSEEK_BUFFERED_TIME); /*clear the lowlevel errors*/
}
else if ( whence == AVSEEK_TO_TIME )
{
if ( 0 ) //(s->UrlCtx.prot->url_exseek)
{
#if 0
if (strcmp(s->prot->name, "vhls") == 0) {// hls can return the stream offset
lp_print( AV_LOG_INFO,"[%s:%d] doing LOOPBUFFER seek\n",__FUNCTION__,__LINE__);
lp_unlock(&lp->mutex);
ret = url_lpexseekoffset(s,offset);
lp_lock(&lp->mutex);
if (ret >= 0) {
s->priv_info = AVSEEK_LOOPBUFFER_OFFSET;
lp_print( AV_LOG_INFO,"[%s:%d] LOOPBUFFER seek deal successful\n",__FUNCTION__,__LINE__);
goto seek_end;
}
s->priv_info = AVSEEK_TO_TIME;
lp_print( AV_LOG_INFO,"[%s:%d] Failed LOOPBUFFER seek\n",__FUNCTION__,__LINE__);
}
#endif
if ( 0 ) // ((ret = s->UrlCtx.prot->url_exseek(s, offset, AVSEEK_TO_TIME)) >= 0)
{
lp -> rp = lp -> buffer ;
lp -> wp = lp -> buffer ;
lp -> valid_data_size = 0 ;
lp -> pos = 0 ;
lp -> decrypt_data_len = 0 ;
lp -> decrypt_read_len = 0 ;
lp -> ts_tail_len = 0 ;
lp -> ts_tail_pos = 0 ;
lp -> need_find_ts_start_pos = 1 ;
goto seek_end ;
}
}
ret = AVERROR ( EPIPE );
}
else if ( whence == AVSEEK_CMF_TS_TIME )
{
if ( 0 ) //(s->UrlCtx.prot->url_exseek)
{
if ( 0 ) //((ret = s->UrlCtx.prot->url_exseek(s, offset, AVSEEK_CMF_TS_TIME)) >= 0)
{
lp -> rp = lp -> buffer ;
lp -> wp = lp -> buffer ;
lp -> valid_data_size = 0 ;
lp -> pos = 0 ;
lp -> decrypt_data_len = 0 ;
lp -> decrypt_read_len = 0 ;
lp -> ts_tail_len = 0 ;
lp -> ts_tail_pos = 0 ;
lp -> need_find_ts_start_pos = 1 ;
goto seek_end ;
}
}
ret = AVERROR ( EPIPE );
}
else if ( whence == AVSEEK_SLICE_BYTIME )
{
ret = s -> prot -> url_seek ( s , offset , AVSEEK_SLICE_BYTIME );
if ( ret < 0 )
{
lp_unlock ( & lp -> mutex );
return - 1 ;
}
lp_unlock ( & lp -> mutex );
return ret ;
}
else if ( whence == AVSEEK_ITEM_TIME )
{
ret = s -> prot -> url_seek ( s , offset , AVSEEK_ITEM_TIME );
if ( ret < 0 )
{
lp_unlock ( & lp -> mutex );
return - 1 ;
}
lp_unlock ( & lp -> mutex );
return ret ;
}
seek_end :
lp_unlock ( & lp -> mutex );
return ret ;
}
int url_lpreset ( URLContext * s )
{
url_lpbuf_t * lp ;
if ( ! s || ! s -> lpbuf )
{
return AVERROR ( EINVAL );
}
lp = s -> lpbuf ;
if ( lp )
{
lp -> rp = lp -> buffer ;
lp -> wp = lp -> buffer ;
lp -> pos = 0 ;
lp -> valid_data_size = 0 ;
lp -> decrypt_data_len = 0 ;
lp -> decrypt_read_len = 0 ;
lp -> ts_tail_len = 0 ;
lp -> ts_tail_pos = 0 ;
}
return 0 ;
}
int url_lp_getbuffering_size ( URLContext * s , int * forward_data , int * back_data )
{
url_lpbuf_t * lp ;
int valid_data_can_seek_forward ;
int valid_data_can_seek_back ;
int ret ;
if ( ! s || ! s -> lpbuf )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
lp_lock ( & lp -> mutex );
if ( lp -> wp >= lp -> rp )
valid_data_can_seek_forward = lp -> wp - lp -> rp ;
else
valid_data_can_seek_forward = lp -> buffer_size - ( lp -> rp - lp -> wp );
valid_data_can_seek_back = FFMIN ( lp -> valid_data_size - valid_data_can_seek_forward ,
lp -> buffer_size - valid_data_can_seek_forward - 64 );
if ( valid_data_can_seek_back < 0 )
valid_data_can_seek_back = 0 ;
lp_unlock ( & lp -> mutex );
if ( forward_data )
* forward_data = valid_data_can_seek_forward ;
if ( back_data )
* back_data = valid_data_can_seek_back ;
return ( valid_data_can_seek_back + valid_data_can_seek_forward );
}
int url_lp_set_seekflags ( URLContext * s , int seekflagmask )
{
url_lpbuf_t * lp ;
if ( ! s || ! s -> lpbuf )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
lp -> seekflags |= seekflagmask ;
return 0 ;
}
int url_lp_clear_seekflags ( URLContext * s , int seekflagmask )
{
url_lpbuf_t * lp ;
if ( ! s || ! s -> lpbuf )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
lp -> seekflags &= ~ seekflagmask ;
return 0 ;
}
int64_t url_lp_get_buffed_pos ( URLContext * s )
{
url_lpbuf_t * lp ;
int64_t pos ;
int buffer_in_cache = 0 ;
if ( ! s || ! s -> lpbuf )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
pos = lp -> pos ;
if ( lp -> cache_enable && ! lp_trylock ( & lp -> mutex ))
{
if ( lp -> cache_enable )
{
buffer_in_cache = aviolp_cache_next_valid_bytes ( lp -> cache_id , pos , INT_MAX );
if ( buffer_in_cache > 0 )
pos += buffer_in_cache ;
}
lp_unlock ( & lp -> mutex );
}
/*lp_sprint(AV_LOG_INFO,"buffered pos=%lld,file_size=%lld,percent=%d.%02d%%,buffer_in_cache=%d\n",
pos,lp->file_size,(int)(pos*100/lp->file_size),(int)((pos*10000/lp->file_size)%100),buffer_in_cache); */
return pos ;
}
int64_t url_buffed_size ( AVIOContext * s )
{
if ( ! s )
return 0 ;
if ( s -> enabled_lp_buffer )
{
int64_t buffed = url_lp_get_buffed_pos ( s -> opaque ) - avio_seek ( s , 0 , SEEK_CUR );
return buffed > 0 ? buffed : 0 ;
}
else
return 0 ;
}
int url_lp_intelligent_buffering ( URLContext * s , int size )
{
int forward_data , back_data ;
int datalen ;
url_lpbuf_t * lp ;
int ret = - 1 ;
if ( ! s || ! s -> lpbuf )
return AVERROR ( EINVAL );
lp = s -> lpbuf ;
lp -> dbg_cnt ++ ;
if ( size <= 0 )
size = lp -> block_read_size ;
datalen = url_lp_getbuffering_size ( s , & forward_data , & back_data );
if ( lp -> dbg_cnt % 100 == 0 )
lp_print ( AV_LOG_DEBUG , "url_lp buffering:datalen=%d,forward_datad=%d,back_data=%d,lp->buffer_size=%d,size=%d \n " ,
datalen , forward_data , back_data , lp -> buffer_size , size );
if ( datalen >= 0 && (( forward_data / lp -> buffer_size ) < lp -> max_forword_level ) &&
(( datalen < lp -> buffer_size - size - 1024 ) || ( back_data > ( forward_data / 2 + 1 )) || ( back_data > 3 * 1024 * 1024 )))
ret = url_lpfillbuffer ( s , size ); /*lest 1/3 back data && < 3M back data*/
return ret ;
}
int url_lpfree ( URLContext * s )
{
if ( s -> lpbuf )
{
lp_lock ( & s -> lpbuf -> mutex );
if ( s -> lpbuf -> cache_enable )
aviolp_cache_close ( s -> lpbuf -> cache_id );
/*release other threadlater...*/
lp_unlock ( & s -> lpbuf -> mutex );
if ( s -> lpbuf -> buffer )
av_free ( s -> lpbuf -> buffer );
if ( s -> lpbuf -> decrypt_data )
av_free ( s -> lpbuf -> decrypt_data );
#if 0
if (s->lpbuf->drm_handle != 0)
{
udrm_decrypt_stop(s->lpbuf->drm_handle);
s->lpbuf->drm_handle = 0;
}
#endif
if ( s -> lpbuf -> fp1 )
{
fclose ( s -> lpbuf -> fp1 );
s -> lpbuf -> fp1 = NULL ;
}
if ( s -> lpbuf -> fp2 )
{
fclose ( s -> lpbuf -> fp2 );
s -> lpbuf -> fp2 = NULL ;
}
av_free ( s -> lpbuf );
s -> lpbuf = NULL ;
}
return 0 ;
}