Upload 5 files
Browse files- app.py +183 -22
- scripts/client_example.py +33 -0
- sources/UNE-153020.txt +73 -0
app.py
CHANGED
|
@@ -507,33 +507,194 @@ if page == "Processar vídeo nou":
|
|
| 507 |
# ]
|
| 508 |
# st.session_state.characters_saved = False
|
| 509 |
|
| 510 |
-
# --- 3. Formularios de personajes ---
|
| 511 |
if st.session_state.characters_detected:
|
| 512 |
-
st.
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 516 |
with col1:
|
| 517 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 518 |
|
|
|
|
| 519 |
with col2:
|
| 520 |
-
st.
|
| 521 |
-
|
| 522 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
# Aquí iría la lógica para
|
| 531 |
-
st.session_state.characters_saved = True
|
| 532 |
-
st.success("Personatges desats correctament.")
|
| 533 |
-
|
| 534 |
-
with col2:
|
| 535 |
-
if st.session_state.characters_saved:
|
| 536 |
-
st.button("Generar Audiodescripció")
|
| 537 |
|
| 538 |
elif page == "Analitzar audio-descripcions":
|
| 539 |
require_login()
|
|
|
|
| 507 |
# ]
|
| 508 |
# st.session_state.characters_saved = False
|
| 509 |
|
| 510 |
+
# --- 3. Formularios de personajes (apilados) ---
|
| 511 |
if st.session_state.characters_detected:
|
| 512 |
+
st.markdown("---")
|
| 513 |
+
st.subheader(f"📋 Personatges detectats: {len(st.session_state.characters_detected)}")
|
| 514 |
+
st.info("Edita cada personatge i confirma el fine-tuning manual al final. Els personatges amb el mateix nom es fusionaran.")
|
| 515 |
+
|
| 516 |
+
# Inicializar datos de personajes si no existe
|
| 517 |
+
if 'character_data' not in st.session_state:
|
| 518 |
+
st.session_state.character_data = {}
|
| 519 |
+
# Inicializar con datos por defecto
|
| 520 |
+
for char in st.session_state.characters_detected:
|
| 521 |
+
char_id = char['id']
|
| 522 |
+
st.session_state.character_data[char_id] = {
|
| 523 |
+
'name': char.get('name', ''),
|
| 524 |
+
'description': '',
|
| 525 |
+
'selected_faces': list(range(char.get('num_faces', 0))), # Todas seleccionadas por defecto
|
| 526 |
+
'selected_voices': [], # Por ahora vacío
|
| 527 |
+
'current_face_idx': 0,
|
| 528 |
+
'current_voice_idx': 0
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
# Mostrar formulario para cada personaje
|
| 532 |
+
for idx, char in enumerate(st.session_state.characters_detected):
|
| 533 |
+
char_id = char['id']
|
| 534 |
+
char_data = st.session_state.character_data[char_id]
|
| 535 |
+
|
| 536 |
+
# Contenedor con borde para cada personaje
|
| 537 |
+
with st.container():
|
| 538 |
+
st.markdown(f"### Personatge {idx + 1}: {char_data['name'] or char_id}")
|
| 539 |
+
|
| 540 |
+
col1, col2 = st.columns([1, 1])
|
| 541 |
+
|
| 542 |
+
# --- Columna 1: Visualizadores ---
|
| 543 |
with col1:
|
| 544 |
+
# Visualizador de caras
|
| 545 |
+
st.markdown("**🖼️ Mostres de cara:**")
|
| 546 |
+
|
| 547 |
+
num_faces = char.get('num_faces', 0)
|
| 548 |
+
if num_faces > 0 and char_data['selected_faces']:
|
| 549 |
+
current_face_idx = char_data['current_face_idx']
|
| 550 |
+
selected_faces = char_data['selected_faces']
|
| 551 |
+
|
| 552 |
+
# Navegación de caras
|
| 553 |
+
col_nav1, col_nav2, col_nav3, col_nav4 = st.columns([1, 2, 1, 1])
|
| 554 |
+
|
| 555 |
+
with col_nav1:
|
| 556 |
+
if st.button("◀", key=f"face_prev_{char_id}", disabled=(current_face_idx == 0)):
|
| 557 |
+
st.session_state.character_data[char_id]['current_face_idx'] = max(0, current_face_idx - 1)
|
| 558 |
+
st.rerun()
|
| 559 |
+
|
| 560 |
+
with col_nav2:
|
| 561 |
+
st.caption(f"Cara {current_face_idx + 1} de {len(selected_faces)}")
|
| 562 |
+
|
| 563 |
+
with col_nav3:
|
| 564 |
+
if st.button("▶", key=f"face_next_{char_id}", disabled=(current_face_idx >= len(selected_faces) - 1)):
|
| 565 |
+
st.session_state.character_data[char_id]['current_face_idx'] = min(len(selected_faces) - 1, current_face_idx + 1)
|
| 566 |
+
st.rerun()
|
| 567 |
+
|
| 568 |
+
with col_nav4:
|
| 569 |
+
if st.button("❌", key=f"face_delete_{char_id}", disabled=(len(selected_faces) <= 1)):
|
| 570 |
+
# Eliminar cara actual
|
| 571 |
+
face_to_remove = selected_faces[current_face_idx]
|
| 572 |
+
st.session_state.character_data[char_id]['selected_faces'].remove(face_to_remove)
|
| 573 |
+
st.session_state.character_data[char_id]['current_face_idx'] = min(current_face_idx, len(selected_faces) - 2)
|
| 574 |
+
st.rerun()
|
| 575 |
+
|
| 576 |
+
# Mostrar imagen de la cara actual
|
| 577 |
+
if 'folder' in char:
|
| 578 |
+
try:
|
| 579 |
+
# Construir URL de la cara
|
| 580 |
+
face_filename = f"face_{selected_faces[current_face_idx]:03d}.jpg"
|
| 581 |
+
face_url = f"{BACKEND_BASE_URL}/files/{st.session_state.video_name}/{char_id}/{face_filename}"
|
| 582 |
+
st.image(face_url, width=250)
|
| 583 |
+
except Exception as e:
|
| 584 |
+
st.info(f"Imatge no disponible: {e}")
|
| 585 |
+
else:
|
| 586 |
+
st.info("No hi ha mostres de cara")
|
| 587 |
+
|
| 588 |
+
st.markdown("---")
|
| 589 |
+
|
| 590 |
+
# Visualizador de voces
|
| 591 |
+
st.markdown("**🎤 Mostres de veu:**")
|
| 592 |
+
st.info("🚧 Funcionalitat de veu en desenvolupament")
|
| 593 |
+
|
| 594 |
+
# TODO: Implementar visualizador de voces similar al de caras
|
| 595 |
|
| 596 |
+
# --- Columna 2: Datos del personaje ---
|
| 597 |
with col2:
|
| 598 |
+
st.markdown("**📝 Informació del personatge:**")
|
| 599 |
+
|
| 600 |
+
# Nombre del personaje
|
| 601 |
+
char_name = st.text_input(
|
| 602 |
+
"Nom del personatge:",
|
| 603 |
+
value=char_data['name'],
|
| 604 |
+
key=f"name_input_{char_id}",
|
| 605 |
+
placeholder="Ex: Maria, Joan, etc.",
|
| 606 |
+
help="Personatges amb el mateix nom es fusionaran"
|
| 607 |
+
)
|
| 608 |
+
|
| 609 |
+
# Actualizar nombre en tiempo real
|
| 610 |
+
if char_name != char_data['name']:
|
| 611 |
+
st.session_state.character_data[char_id]['name'] = char_name
|
| 612 |
+
|
| 613 |
+
# Descripción
|
| 614 |
+
char_description = st.text_area(
|
| 615 |
+
"Descripció (text lliure):",
|
| 616 |
+
value=char_data['description'],
|
| 617 |
+
key=f"desc_input_{char_id}",
|
| 618 |
+
placeholder="Ex: Dona d'uns 30 anys, cabell ros, ulleres...",
|
| 619 |
+
height=150
|
| 620 |
+
)
|
| 621 |
+
|
| 622 |
+
# Actualizar descripción en tiempo real
|
| 623 |
+
if char_description != char_data['description']:
|
| 624 |
+
st.session_state.character_data[char_id]['description'] = char_description
|
| 625 |
+
|
| 626 |
+
# Información adicional
|
| 627 |
+
st.caption(f"**ID original:** {char_id}")
|
| 628 |
+
st.caption(f"**Caras seleccionades:** {len(char_data['selected_faces'])} de {num_faces}")
|
| 629 |
+
|
| 630 |
+
st.markdown("---")
|
| 631 |
+
|
| 632 |
+
# --- 4. Botón de confirmación de fine-tuning ---
|
| 633 |
+
st.markdown("### 🎯 Confirmació del fine-tuning manual")
|
| 634 |
+
|
| 635 |
+
if st.button("✅ Confirmar fine-tuning i fusionar personatges", type="primary", use_container_width=True):
|
| 636 |
+
# Agrupar personajes por nombre
|
| 637 |
+
merged_characters = {}
|
| 638 |
+
|
| 639 |
+
for char in st.session_state.characters_detected:
|
| 640 |
+
char_id = char['id']
|
| 641 |
+
char_data = st.session_state.character_data[char_id]
|
| 642 |
+
char_name = char_data['name'].strip()
|
| 643 |
+
|
| 644 |
+
if not char_name:
|
| 645 |
+
char_name = f"Personatge sense nom {char_id}"
|
| 646 |
+
|
| 647 |
+
if char_name not in merged_characters:
|
| 648 |
+
merged_characters[char_name] = {
|
| 649 |
+
'id': f"merged_{len(merged_characters) + 1}",
|
| 650 |
+
'name': char_name,
|
| 651 |
+
'description': char_data['description'],
|
| 652 |
+
'selected_faces': [],
|
| 653 |
+
'selected_voices': [],
|
| 654 |
+
'original_ids': []
|
| 655 |
+
}
|
| 656 |
+
|
| 657 |
+
# Fusionar datos
|
| 658 |
+
merged_characters[char_name]['selected_faces'].extend(char_data['selected_faces'])
|
| 659 |
+
merged_characters[char_name]['selected_voices'].extend(char_data['selected_voices'])
|
| 660 |
+
merged_characters[char_name]['original_ids'].append(char_id)
|
| 661 |
+
|
| 662 |
+
# Fusionar descripciones (concatenar si hay múltiples)
|
| 663 |
+
if char_data['description'] and char_data['description'] not in merged_characters[char_name]['description']:
|
| 664 |
+
if merged_characters[char_name]['description']:
|
| 665 |
+
merged_characters[char_name]['description'] += " | " + char_data['description']
|
| 666 |
+
else:
|
| 667 |
+
merged_characters[char_name]['description'] = char_data['description']
|
| 668 |
+
|
| 669 |
+
# Actualizar personajes con los fusionados
|
| 670 |
+
st.session_state.characters_detected = list(merged_characters.values())
|
| 671 |
+
|
| 672 |
+
# Reinicializar character_data con los nuevos personajes
|
| 673 |
+
st.session_state.character_data = {}
|
| 674 |
+
for char in st.session_state.characters_detected:
|
| 675 |
+
char_id = char['id']
|
| 676 |
+
st.session_state.character_data[char_id] = {
|
| 677 |
+
'name': char['name'],
|
| 678 |
+
'description': char['description'],
|
| 679 |
+
'selected_faces': char['selected_faces'],
|
| 680 |
+
'selected_voices': char['selected_voices'],
|
| 681 |
+
'current_face_idx': 0,
|
| 682 |
+
'current_voice_idx': 0
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
# Marcar como guardados
|
| 686 |
+
st.session_state.characters_saved = True
|
| 687 |
+
st.success(f"✅ Fine-tuning confirmat! {len(merged_characters)} personatges finals.")
|
| 688 |
+
st.balloons()
|
| 689 |
+
st.rerun()
|
| 690 |
|
| 691 |
+
# --- 5. Botón para generar audiodescripción (solo si están guardados) ---
|
| 692 |
+
if st.session_state.characters_saved:
|
| 693 |
+
st.markdown("---")
|
| 694 |
+
st.markdown("### 🎬 Generar audiodescripció")
|
| 695 |
+
if st.button("🎬 Generar Audiodescripció", type="primary", use_container_width=True):
|
| 696 |
+
st.info("🚧 Funcionalitat en desenvolupament...")
|
| 697 |
+
# Aquí iría la lógica para generar la audiodescripción
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 698 |
|
| 699 |
elif page == "Analitzar audio-descripcions":
|
| 700 |
require_login()
|
scripts/client_example.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# =====================================
|
| 2 |
+
# File: client_example.py (opcional)
|
| 3 |
+
# =====================================
|
| 4 |
+
import requests
|
| 5 |
+
|
| 6 |
+
class VeureuEngineClient:
|
| 7 |
+
def __init__(self, base_url: str):
|
| 8 |
+
self.base = base_url.rstrip("/")
|
| 9 |
+
|
| 10 |
+
def process_video(self, video_path: str, **kwargs):
|
| 11 |
+
with open(video_path, "rb") as f:
|
| 12 |
+
files = {"video_file": (Path(video_path).name, f, "video/mp4")}
|
| 13 |
+
data = {"config_path": kwargs.get("config_path", "config_veureu.yaml"),
|
| 14 |
+
"out_root": kwargs.get("out_root", "results"),
|
| 15 |
+
"db_dir": kwargs.get("db_dir", "chroma_db")}
|
| 16 |
+
r = requests.post(f"{self.base}/process_video", files=files, data=data, timeout=3600)
|
| 17 |
+
r.raise_for_status()
|
| 18 |
+
return r.json()
|
| 19 |
+
|
| 20 |
+
def load_casting(self, faces_dir: str, voices_dir: str, db_dir: str = "chroma_db", drop_collections: bool = False):
|
| 21 |
+
data = {"faces_dir": faces_dir, "voices_dir": voices_dir, "db_dir": db_dir, "drop_collections": str(drop_collections)}
|
| 22 |
+
r = requests.post(f"{self.base}/load_casting", data=data, timeout=600)
|
| 23 |
+
r.raise_for_status(); return r.json()
|
| 24 |
+
|
| 25 |
+
def refine_narration(self, dialogues_srt: str, frame_descriptions: list, model_url: str, une_guidelines_path: str):
|
| 26 |
+
data = {
|
| 27 |
+
"dialogues_srt": dialogues_srt,
|
| 28 |
+
"frame_descriptions_json": json.dumps(frame_descriptions, ensure_ascii=False),
|
| 29 |
+
"model_url": model_url,
|
| 30 |
+
"une_guidelines_path": une_guidelines_path,
|
| 31 |
+
}
|
| 32 |
+
r = requests.post(f"{self.base}/refine_narration", data=data, timeout=600)
|
| 33 |
+
r.raise_for_status(); return r.json()
|
sources/UNE-153020.txt
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
1. DEFINICIÓN Y OBJETIVO
|
| 2 |
+
|
| 3 |
+
La audiodescripción (AD) es un servicio de apoyo a la comunicación para las personas ciegas o con baja visión, regulado por la norma UNE 153020 y que consiste en compensar la falta de información visual relevante para la comprensión global y el disfrute del producto audiovisual con la descripción objetiva, clara y sucinta de las imágenes, de modo que las personas con discapacidad visual lo perciban de la forma más parecida posible a como lo hacen las personas videntes.
|
| 4 |
+
|
| 5 |
+
2. PAUTAS
|
| 6 |
+
2.1. ¿QUÉ INFORMACIÓN SE AUDIODESCRIBE?
|
| 7 |
+
|
| 8 |
+
Se debe tratar de informar de:
|
| 9 |
+
● CUÁNDO Y DÓNDE (Describir lugares y dimensiones, hora del día, si está oscuro…)
|
| 10 |
+
“En un callejón oscuro…”
|
| 11 |
+
“Es de día, una señora anda por la calle”.
|
| 12 |
+
● QUIÉN (Describir e identificar, ropa, atributos físicos, etnia si es relevante…)
|
| 13 |
+
● QUÉ (Respuestas no verbales, relacionadas con el diálogo)
|
| 14 |
+
● CÓMO
|
| 15 |
+
|
| 16 |
+
Solo se audiodescribe la información que aporta algo.
|
| 17 |
+
2.2. ¿CUÁNDO SE AUDIODESCRIBE?
|
| 18 |
+
|
| 19 |
+
Se audiodescribe en los huecos o silencios. Si las personas en escena están hablando, no podemos audiodescribir por encima. En los programas de televisión, sobre todo en los más dinámicos, suele haber poca cabida para audiodescribir.
|
| 20 |
+
|
| 21 |
+
En ocasiones, hay silencios relevantes para la trama y hay que respetarlos (Para generar sensación de suspense, por motivos cómicos…). Esas veces hay que dejar que el programa audiovisual “respire” por sí mismo, evitando audiodescribir lo que es obvio o ya viene transmitido en la pista sonora (diálogos o ruidos)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
2.2. LENGUAJE EN LA AUDIODESCRIPCIÓN
|
| 25 |
+
|
| 26 |
+
● Siempre desde la perspectiva del espectador. Describimos lo que nosotros vemos como espectadores, sin información privilegiada.
|
| 27 |
+
● Se describe en PRESENTE
|
| 28 |
+
“Broncano se agacha”.
|
| 29 |
+
● VALOR NARRATIVO: Se describe el lenguaje corporal, las expresiones faciales, los movimientos…
|
| 30 |
+
“María lo mira asombrada”.
|
| 31 |
+
“Kevin guiña un ojo”.
|
| 32 |
+
● El vocabulario debe ser EXPRESIVO: lleno de significado
|
| 33 |
+
● Objetividad y claridad
|
| 34 |
+
● Se premia la riqueza léxica. Adjetivos específicos (“astuto” mejor que “malo”).
|
| 35 |
+
● Lenguaje conciso
|
| 36 |
+
● Adaptarse al tono y estilo del contenido (sin lenguaje ofensivo, a menos que aparezca como texto en pantalla)
|
| 37 |
+
● Los logotipos y títulos se describen
|
| 38 |
+
● Evitar la voz pasiva.
|
| 39 |
+
● Si hay cortes o cambios de tiempo, se indica. (Característica de películas y series)
|
| 40 |
+
“3 años después…”.
|
| 41 |
+
“Valencia, 1995”.
|
| 42 |
+
● También se audiodescriben las cabeceras, aunque siempre sea la misma.
|
| 43 |
+
● También se audiodescribe el texto en pantalla
|
| 44 |
+
|
| 45 |
+
2.3. ERRORES A EVITAR
|
| 46 |
+
|
| 47 |
+
- Evitar: metáforas, coloquialismos, regionalismos, léxico cinematográfico, los verbos “aparecer, ver…”.
|
| 48 |
+
Las siguientes descripciones serían incorrectas:
|
| 49 |
+
“Ramón aparece en escena…”
|
| 50 |
+
“Vemos al niño saltar…”
|
| 51 |
+
“En primer plano, Lucía…”
|
| 52 |
+
- No interpretar, debemos ser neutros y objetivos
|
| 53 |
+
- No explicar más de lo que se ve ni hacer suposiciones
|
| 54 |
+
- No ser demasiado literario ni didáctico.
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
3. LOCUCIÓN
|
| 58 |
+
|
| 59 |
+
En cuanto a la locución, se recomienda el uso de voz profesional, neutra y con buena dicción. No obstante, en el ámbito educativo, así como en otros contextos como los museos o el teatro, se ha utilizado motores de síntesis de voz para generar la locución de audiodescripción. Esta práctica no está recogida en la norma.
|
| 60 |
+
|
| 61 |
+
“Las locuciones deben ser neutras y la dicción correcta (entonación, ritmo y vocalización adecuados), debiendo evitarse la entonación afectiva". Para obras infantiles, "se recomienda que el locutor o locutora utilice una entonación adecuada para niños, pudiendo ser algo más expresiva" (AENOR, 2005, p. 9).
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
4. FORMATO
|
| 65 |
+
|
| 66 |
+
Formato ESEF (*.esf) El formato ESEF es un estándar de la industria audiovisual para la producción y reproducción la audiodescripción en entornos de emisión de televisión.
|
| 67 |
+
|
| 68 |
+
Este formato maneja archivos de audio en formato Broadcast WAV (BWF).
|
| 69 |
+
|
| 70 |
+
Una de las ventajas de este formato es que almacena toda la información de la audiodescripción de manera independiente del contenido audiodescrito. Este formato contiene por separado la información del guión (texto temporizado), los contenidos de la locución en ficheros independientes y la configuración para garantizar una mezcla de la banda sonora en el destino.
|
| 71 |
+
|
| 72 |
+
Este formato debe manipularse solamente con herramientas profesionales específicas de audiodescripción.
|
| 73 |
+
|