一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術(shù)及教程分享平臺!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Python - 用Python的Django框架完成視頻處理任務(wù)的教程

用Python的Django框架完成視頻處理任務(wù)的教程

2020-05-28 10:16stickyworld Python

這篇文章主要介紹了用Python的Django框架完成視頻處理任務(wù)的教程,包括用戶的視頻上傳和播放以及下載功能的實(shí)現(xiàn),需要的朋友可以參考下

Stickyworld 的網(wǎng)頁應(yīng)用已經(jīng)支持視頻撥放一段時(shí)間,但都是通過YouTube的嵌入模式實(shí)現(xiàn)。我們開始提供新的版本支持視頻操作,可以讓我們的用戶不用受制于YouTube的服務(wù)。

我過去曾經(jīng)參與過一個(gè)項(xiàng)目,客戶需要視頻轉(zhuǎn)碼功能,這實(shí)在不是個(gè)容易達(dá)成的需求。需要大量的讀取每一個(gè)視頻、音訊與視頻容器的格式再輸出符合網(wǎng)頁使用與喜好的視頻格式。

考慮到這一點(diǎn),我們決定將轉(zhuǎn)碼的工作交給 Encoding.com 。這個(gè)網(wǎng)站可以免費(fèi)讓你編碼1GB大小的視頻,超過1GB容量的文件將采取分級計(jì)價(jià)收費(fèi)。

開發(fā)的代碼如下,我上傳了一個(gè)178KB容量的兩秒視頻來測試代碼是否成功運(yùn)作。當(dāng)測試過程沒有發(fā)生任何的例外錯(cuò)誤后,我繼續(xù)測試其它更大的外部文件。

 
階段一:用戶上傳視頻文件

現(xiàn)在這的新的代碼段提供了一個(gè)基于 HTML5且可以快速上手的 的上傳機(jī)制。用CoffeeScript撰寫的代碼,可以從客戶端上傳文件到服務(wù)器端。
 

?
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
$scope.upload_slide = (upload_slide_form) ->
  file = document.getElementById("slide_file").files[0]
  reader = new FileReader()
  reader.readAsDataURL file
  reader.onload = (event) ->
   result = event.target.result
   fileName = document.getElementById("slide_file").files[0].name
   $.post "/world/upload_slide",
    data: result
    name: fileName
    room_id: $scope.room.id
    (response_data) ->
     if response_data.success? is not yes
      console.error "There was an error uploading the file", response_data
     else
      console.log "Upload successful", response_data
  reader.onloadstart = ->
   console.log "onloadstart"
  reader.onprogress = (event) ->
   console.log "onprogress", event.total, event.loaded, (event.loaded / event.total) * 100
  reader.onabort = ->
   console.log "onabort"
  reader.onerror = ->
   console.log "onerror"
  reader.onloadend = (event) ->
   console.log "onloadend", event

最好可以通過 (“slide_file”).files 且經(jīng)由獨(dú)立的POST上傳每個(gè)文件,而不是由一個(gè)POST需求上傳所有文件。稍后我們會(huì)解釋這點(diǎn)。

 
階段二:驗(yàn)證并上傳至 Amazon S3

后端我們運(yùn)行了Django與RabbitMQ。主要的模塊如下:
 

?
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
$ pip install 'Django>=1.5.2' 'django-celery>=3.0.21' \
  'django-storages>=1.1.8' 'lxml>=3.2.3' 'python-magic>=0.4.3'
 
我建立了兩個(gè)模塊:SlideUploadQueue 用來儲存每一次上傳的數(shù)據(jù),SlideVideoMedia 則是用來儲存每個(gè)要上傳影片的數(shù)據(jù)。
 
class SlideUploadQueue(models.Model):
  created_by = models.ForeignKey(User)
  created_time = models.DateTimeField(db_index=True)
  original_file = models.FileField(
    upload_to=filename_sanitiser, blank=True, default='')
  media_type = models.ForeignKey(MediaType)
  encoding_com_tracking_code = models.CharField(
    default='', max_length=24, blank=True)
 
  STATUS_AWAITING_DATA = 0
  STATUS_AWAITING_PROCESSING = 1
  STATUS_PROCESSING = 2
  STATUS_AWAITING_3RD_PARTY_PROCESSING = 5
  STATUS_FINISHED = 3
  STATUS_FAILED = 4
 
  STATUS_LIST = (
    (STATUS_AWAITING_DATA, 'Awaiting Data'),
    (STATUS_AWAITING_PROCESSING, 'Awaiting processing'),
    (STATUS_PROCESSING, 'Processing'),
    (STATUS_AWAITING_3RD_PARTY_PROCESSING,
      'Awaiting 3rd-party processing'),
    (STATUS_FINISHED, 'Finished'),
    (STATUS_FAILED, 'Failed'),
  )
 
  status = models.PositiveSmallIntegerField(
    default=STATUS_AWAITING_DATA, choices=STATUS_LIST)
 
  class Meta:
    verbose_name = 'Slide'
    verbose_name_plural = 'Slide upload queue'
 
  def save(self, *args, **kwargs):
    if not self.created_time:
      self.created_time = \
        datetime.utcnow().replace(tzinfo=pytz.utc)
 
    return super(SlideUploadQueue, self).save(*args, **kwargs)
 
  def __unicode__(self):
    if self.id is None:
      return 'new <SlideUploadQueue>'
    return '<SlideUploadQueue> %d' % self.id
 
class SlideVideoMedia(models.Model):
  converted_file = models.FileField(
    upload_to=filename_sanitiser, blank=True, default='')
 
  FORMAT_MP4 = 0
  FORMAT_WEBM = 1
  FORMAT_OGG = 2
  FORMAT_FL9 = 3
  FORMAT_THUMB = 4
 
  supported_formats = (
    (FORMAT_MP4, 'MPEG 4'),
    (FORMAT_WEBM, 'WebM'),
    (FORMAT_OGG, 'OGG'),
    (FORMAT_FL9, 'Flash 9 Video'),
    (FORMAT_THUMB, 'Thumbnail'),
  )
 
  mime_types = (
    (FORMAT_MP4, 'video/mp4'),
    (FORMAT_WEBM, 'video/webm'),
    (FORMAT_OGG, 'video/ogg'),
    (FORMAT_FL9, 'video/mp4'),
    (FORMAT_THUMB, 'image/jpeg'),
  )
 
  format = models.PositiveSmallIntegerField(
    default=FORMAT_MP4, choices=supported_formats)
 
  class Meta:
    verbose_name = 'Slide video'
    verbose_name_plural = 'Slide videos'
 
  def __unicode__(self):
    if self.id is None:
      return 'new <SlideVideoMedia>'
    return '<SlideVideoMedia> %d' % self.id

我們的模塊皆使用 filename_sanitiser。FileField 自動(dòng)的將文件名調(diào)整成 <model>/<uuid4>.<extention> 格式。整理每個(gè)文件名并確保其獨(dú)一性。我們采用了有時(shí)效性簽署的網(wǎng)址列讓我們可以掌控哪些使用者在使用我們的服務(wù),使用了多久。
 

?
1
2
3
4
5
6
7
8
9
10
11
def filename_sanitiser(instance, filename):
  folder = instance.__class__.__name__.lower()
  ext = 'jpg'
 
  if '.' in filename:
    t_ext = filename.split('.')[-1].strip().lower()
 
    if t_ext != '':
      ext = t_ext
 
  return '%s/%s.%s' % (folder, str(uuid.uuid4()), ext)

拿來測試的文件 testing.mov 將會(huì)轉(zhuǎn)換成以下網(wǎng)址:https://our-bucket.s3.amazonaws.com/slideuploadqueue/3fe27193-e87f-4244-9aa2-66409f70ebd3.mov 并經(jīng)由Django Storages 模塊上傳。

我們通過 Magic 驗(yàn)證從使用者端瀏覽器上傳的文件。Magic可以從文件內(nèi)容偵測是何種類型的文件。
 

?
1
2
3
4
5
6
@verify_auth_token
@return_json
def upload_slide(request):
  file_data = request.POST.get('data', '')
  file_data = base64.b64decode(file_data.split(';base64,')[1])
  description = magic.from_buffer(file_data)

如果文件類型符合MPEG v4 系統(tǒng)或是Apple QuickTime 電影,我們就知道該文件轉(zhuǎn)碼不會(huì)有太大問題。如果格式不是上述所提的幾種,我們會(huì)標(biāo)志給用戶知悉。
接著,我們將通過SlideUploadQueue 模塊將視頻儲存到隊(duì)列并發(fā)送一個(gè)需求給 RabbitMQ。因?yàn)槲覀兪褂昧薉jango Storages 模塊,文件將自動(dòng)被上傳到 Amazon S3。
 

?
1
2
3
4
5
6
7
8
9
10
slide_upload = SlideUploadQueue()
...
slide_upload.status = SlideUploadQueue.STATUS_AWAITING_PROCESSING
slide_upload.save()
slide_upload.original_file.\
  save('anything.%s' % file_ext, ContentFile(file_data))
slide_upload.save()
 
task = ConvertRawSlideToSlide()
task.delay(slide_upload)

階段3:發(fā)送視頻到第三方.

RabbitMQ 將控管 task.delay(slide_upload) 的呼叫。
我們現(xiàn)在只需要發(fā)送視頻檔網(wǎng)址與輸出格式給Encoding.com。該網(wǎng)站會(huì)回復(fù)我們一個(gè)工作碼讓我們檢查視頻轉(zhuǎn)碼的進(jìn)度。

?
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
class ConvertRawSlideToSlide(Task):
  queue = 'backend_convert_raw_slides'
  ...
  def _handle_video(self, slide_upload):
    mp4 = {
      'output': 'mp4',
      'size': '320x240',
      'bitrate': '256k',
      'audio_bitrate': '64k',
      'audio_channels_number': '2',
      'keep_aspect_ratio': 'yes',
      'video_codec': 'mpeg4',
      'profile': 'main',
      'vcodecparameters': 'no',
      'audio_codec': 'libfaac',
      'two_pass': 'no',
      'cbr': 'no',
      'deinterlacing': 'no',
      'keyframe': '300',
      'audio_volume': '100',
      'file_extension': 'mp4',
      'hint': 'no',
    }
 
    webm = {
      'output': 'webm',
      'size': '320x240',
      'bitrate': '256k',
      'audio_bitrate': '64k',
      'audio_sample_rate': '44100',
      'audio_channels_number': '2',
      'keep_aspect_ratio': 'yes',
      'video_codec': 'libvpx',
      'profile': 'baseline',
      'vcodecparameters': 'no',
      'audio_codec': 'libvorbis',
      'two_pass': 'no',
      'cbr': 'no',
      'deinterlacing': 'no',
      'keyframe': '300',
      'audio_volume': '100',
      'preset': '6',
      'file_extension': 'webm',
      'acbr': 'no',
    }
 
    ogg = {
      'output': 'ogg',
      'size': '320x240',
      'bitrate': '256k',
      'audio_bitrate': '64k',
      'audio_sample_rate': '44100',
      'audio_channels_number': '2',
      'keep_aspect_ratio': 'yes',
      'video_codec': 'libtheora',
      'profile': 'baseline',
      'vcodecparameters': 'no',
      'audio_codec': 'libvorbis',
      'two_pass': 'no',
      'cbr': 'no',
      'deinterlacing': 'no',
      'keyframe': '300',
      'audio_volume': '100',
      'file_extension': 'ogg',
      'acbr': 'no',
    }
 
    flv = {
      'output': 'fl9',
      'size': '320x240',
      'bitrate': '256k',
      'audio_bitrate': '64k',
      'audio_channels_number': '2',
      'keep_aspect_ratio': 'yes',
      'video_codec': 'libx264',
      'profile': 'high',
      'vcodecparameters': 'no',
      'audio_codec': 'libfaac',
      'two_pass': 'no',
      'cbr': 'no',
      'deinterlacing': 'no',
      'keyframe': '300',
      'audio_volume': '100',
      'file_extension': 'mp4',
    }
 
    thumbnail = {
      'output': 'thumbnail',
      'time': '5',
      'video_codec': 'mjpeg',
      'keep_aspect_ratio': 'yes',
      'file_extension': 'jpg',
    }
 
    encoder = Encoding(settings.ENCODING_API_USER_ID,
      settings.ENCODING_API_USER_KEY)
    resp = encoder.add_media(source=[slide_upload.original_file.url],
      formats=[mp4, webm, ogg, flv, thumbnail])
 
    media_id = None
 
    if resp is not None and resp.get('response') is not None:
      media_id = resp.get('response').get('MediaID')
 
    if media_id is None:
      slide_upload.status = SlideUploadQueue.STATUS_FAILED
      slide_upload.save()
      log.error('Unable to communicate with encoding.com')
      return False
 
    slide_upload.encoding_com_tracking_code = media_id
    slide_upload.status = \
      SlideUploadQueue.STATUS_AWAITING_3RD_PARTY_PROCESSING
    slide_upload.save()
    return True

Encoding.com 推薦一些堪用的Python程序,可用來與它們的服務(wù)溝通。我修改了模塊一些地方,但還需要修改一些功能才能達(dá)到我滿意的狀態(tài)。以下是修改過后目前正在使用的程序代碼:

?
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
import httplib
from lxml import etree
import urllib
from xml.parsers.expat import ExpatError
import xmltodict
 
ENCODING_API_URL = 'manage.encoding.com:80'
 
class Encoding(object):
 
  def __init__(self, userid, userkey, url=ENCODING_API_URL):
    self.url = url
    self.userid = userid
    self.userkey = userkey
 
  def get_media_info(self, action='GetMediaInfo', ids=[],
    headers={'Content-Type': 'application/x-www-form-urlencoded'}):
    query = etree.Element('query')
 
    nodes = {
      'userid': self.userid,
      'userkey': self.userkey,
      'action': action,
      'mediaid': ','.join(ids),
    }
 
    query = self._build_tree(etree.Element('query'), nodes)
    results = self._execute_request(query, headers)
 
    return self._parse_results(results)
 
  def get_status(self, action='GetStatus', ids=[], extended='no',
    headers={'Content-Type': 'application/x-www-form-urlencoded'}):
    query = etree.Element('query')
 
    nodes = {
      'userid': self.userid,
      'userkey': self.userkey,
      'action': action,
      'extended': extended,
      'mediaid': ','.join(ids),
    }
 
    query = self._build_tree(etree.Element('query'), nodes)
    results = self._execute_request(query, headers)
 
    return self._parse_results(results)
 
  def add_media(self, action='AddMedia', source=[], notify='', formats=[],
    instant='no',
    headers={'Content-Type': 'application/x-www-form-urlencoded'}):
    query = etree.Element('query')
 
    nodes = {
      'userid': self.userid,
      'userkey': self.userkey,
      'action': action,
      'source': source,
      'notify': notify,
      'instant': instant,
    }
 
    query = self._build_tree(etree.Element('query'), nodes)
 
    for format in formats:
      format_node = self._build_tree(etree.Element('format'), format)
      query.append(format_node)
 
    results = self._execute_request(query, headers)
    return self._parse_results(results)
 
  def _build_tree(self, node, data):
    for k, v in data.items():
      if isinstance(v, list):
        for item in v:
          element = etree.Element(k)
          element.text = item
          node.append(element)
      else:
        element = etree.Element(k)
        element.text = v
        node.append(element)
 
    return node
 
  def _execute_request(self, xml, headers, path='', method='POST'):
    params = urllib.urlencode({'xml': etree.tostring(xml)})
 
    conn = httplib.HTTPConnection(self.url)
    conn.request(method, path, params, headers)
    response = conn.getresponse()
    data = response.read()
    conn.close()
    return data
 
  def _parse_results(self, results):
    try:
      return xmltodict.parse(results)
    except ExpatError, e:
      print 'Error parsing encoding.com response'
      print e
      return None

其他待完成事項(xiàng)包括通過HTTPS-only (加密聯(lián)機(jī)) 使用Encoding.com 嚴(yán)謹(jǐn)?shù)腟SL驗(yàn)證,還有一些單元測試。
階段4:下載所有新的視頻檔格式

我們有個(gè)定期執(zhí)行的程序,通過RabbitMQ每15秒檢查視頻轉(zhuǎn)碼的進(jìn)度:
 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CheckUpOnThirdParties(PeriodicTask):
  run_every = timedelta(seconds=settings.THIRD_PARTY_CHECK_UP_INTERVAL)
  ...
  def _handle_encoding_com(self, slides):
    format_lookup = {
      'mp4': SlideVideoMedia.FORMAT_MP4,
      'webm': SlideVideoMedia.FORMAT_WEBM,
      'ogg': SlideVideoMedia.FORMAT_OGG,
      'fl9': SlideVideoMedia.FORMAT_FL9,
      'thumbnail': SlideVideoMedia.FORMAT_THUMB,
    }
 
    encoder = Encoding(settings.ENCODING_API_USER_ID,
      settings.ENCODING_API_USER_KEY)
 
    job_ids = [item.encoding_com_tracking_code for item in slides]
    resp = encoder.get_status(ids=job_ids)
 
    if resp is None:
      log.error('Unable to check up on encoding.com')
      return False

檢查Encoding.com的響應(yīng)來驗(yàn)證每個(gè)部分是否正確以利我們繼續(xù)下去。

?
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
if resp.get('response') is None:
  log.error('Unable to get response node from encoding.com')
  return False
 
resp_id = resp.get('response').get('id')
 
if resp_id is None:
  log.error('Unable to get media id from encoding.com')
  return False
 
slide = SlideUploadQueue.objects.filter(
  status=SlideUploadQueue.STATUS_AWAITING_3RD_PARTY_PROCESSING,
  encoding_com_tracking_code=resp_id)
 
if len(slide) != 1:
  log.error('Unable to find a single record for %s' % resp_id)
  return False
 
resp_status = resp.get('response').get('status')
 
if resp_status is None:
  log.error('Unable to get status from encoding.com')
  return False
 
if resp_status != u'Finished':
  log.debug("%s isn't finished, will check back later" % resp_id)
  return True
 
formats = resp.get('response').get('format')
 
if formats is None:
  log.error("No output formats were found. Something's wrong.")
  return False
 
for format in formats:
  try:
    assert format.get('status') == u'Finished', \
    "%s is not finished. Something's wrong." % format.get('id')
 
    output = format.get('output')
    assert output in ('mp4', 'webm', 'ogg', 'fl9',
      'thumbnail'), 'Unknown output format %s' % output
 
    s3_dest = format.get('s3_destination')
    assert 'http://encoding.com.result.s3.amazonaws.com/'\
      in s3_dest, 'Suspicious S3 url: %s' % s3_dest
 
    https_link = \
      'https://s3.amazonaws.com/encoding.com.result/%s' %\
      s3_dest.split('/')[-1]
    file_ext = https_link.split('.')[-1].strip()
 
    assert len(file_ext) > 0,\
      'Unable to get file extension from %s' % https_link
 
    count = SlideVideoMedia.objects.filter(slide_upload=slide,
      format=format_lookup[output]).count()
 
    if count != 0:
      print 'There is already a %s file for this slide' % output
      continue
 
    content = self.download_content(https_link)
 
    assert content is not None,\
      'There is no content for %s' % format.get('id')
  except AssertionError, e:
    log.error('A format did not pass all assertions: %s' % e)
    continue

到這里我們已確認(rèn)所有事項(xiàng)皆正常,所以我們可以儲存所有的視頻檔了:
 

?
1
2
3
4
media = SlideVideoMedia()
media.format = format_lookup[output]
media.converted_file.save('blah.%s' % file_ext, ContentFile(content))
media.save()

階段5:經(jīng)由HTML5播放視頻檔

在我們的前端網(wǎng)頁已經(jīng)新增了一個(gè)有HTML5的影像單元的網(wǎng)頁。并采用對每個(gè)瀏覽器都有最佳支持的video.js來顯示視頻。
 

?
1
2
3
4
5
6
7
? bower install video.js
bower caching git://github.com/videojs/video.js-component.git
bower cloning git://github.com/videojs/video.js-component.git
bower fetching video.js
bower checking out video.js#v4.0.3
bower copying /home/mark/.bower/cache/video.js/5ab058cd60c5615aa38e8e706cd0f307
bower installing video.js#4.0.3

在我們的首頁有包含其他相依的文件:
 

?
1
2
3
4
5
6
7
!!! 5
html(lang="en", class="no-js")
 head
  meta(http-equiv='Content-Type', content='text/html; charset=UTF-8')
  ...
  link(rel='stylesheet', type='text/css', href='/components/video-js-4.1.0/video-js.css')
  script(type='text/javascript', src='/components/video-js-4.1.0/video.js')

在Angular.js/JADE-based 框架下的模塊,我們引入<video>卷標(biāo) 與其<source>子卷標(biāo)。每個(gè)視頻文件都會(huì)有縮圖通過<video>卷標(biāo)的 poster 組件顯示,縮圖的圖像是由我們從視頻的前幾秒擷取下來。
 

?
1
2
3
#main.span12
  video#example_video_1.video-js.vjs-default-skin(controls, preload="auto", width="640", height="264", poster="{{video_thumbnail}}", data-setup='{"example_option":true}', ng-show="videos")
    source(ng-repeat="video in videos", src="{{video.src}}", type="{{video.type}}")

還會(huì)顯示出我們轉(zhuǎn)換的每個(gè)視頻文件格式,并使用在<source>標(biāo)簽。Video.js 會(huì)根據(jù)使用者使用的瀏覽器決定播放哪種格式的視頻。

我們?nèi)匀挥性S多工作需要完成,建立單元測試與加強(qiáng)和Encoding.com服務(wù)溝通的程序。如果你對這些工作感興趣請與我連絡(luò)。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲精品色综合久久 | 1024视频色版在线网站 | 古代翁熄系小说辣文 | 日韩欧美推理片免费在线播放 | 猫咪社区在线播放 | 婷婷丁香视频 | 91视频免费观看网站 | 农夫成人网 | 九九99热| 国产欧美日韩在线播放 | 精品一成人岛国片在线观看 | 白丝捆绑调教 | 日本精品久久久久久久久免费 | 亚洲社区在线观看 | 成人影院vs一区二区 | 国产梦呦精品 | 亚洲va久久久噜噜噜久久狠狠 | naruto tube18动漫 mm131亚洲精品久久 | 亚洲成a人不卡在线观看 | 欧美在线播放成人免费 | 吉川爱美与黑人解禁 | 日韩日日日 | 性做久久久久久 | 激情视频在线播放 | 欧美精品亚洲精品日韩1818 | 唯美清纯 自拍偷 | 男人的j插入女人的p | 91在线 一区 二区三区 | 日本免费在线观看 | 亚洲欧美国产精品久久久 | 青青青久热国产精品视频 | 日本老妇和子乱视频 | 操美女bb | 91色香sxmv最网页版新地址 | 手机在线观看伦理片 | 喷奶水榨乳ova动漫无修 | 无限时间看片在线观看 | 国产精品国产国产aⅴ | 午夜影院小视频 | 日本xnxnxnxnxn护士 | 亚洲国产成人综合 |